Skip to content

Share directories from one container to othersβ€”automatically works across servers. Perfect for multi-service applications, team collaboration, and data exchange without duplicating files.


Complete Storage Shares API:

Creating & Managing Shares:

Receiving & Mounting Shares:


Storage shares use a two-party system:

Source Container Decides WHAT

Share Creator Controls:

  • Which directory to share (source_path)
  • Access mode (readonly or readwrite)
  • Who can access (1-to-1 or project-wide)
  • When it expires (optional)
  • Enable/disable anytime

Target Container Decides IF

Share Receiver Controls:

  • Whether to mount the share
  • Can reject shares they don’t need
  • Can unmount anytime
  • Independent of share status

Key principle: Source controls WHAT. Target controls IF.


Share specific directory with ONE container:

Terminal window
# Create 1-to-1 container share (readonly)
hoody storage create --container $SOURCE_ID \
--source-path "/hoody/storage/shared-assets" \
--target-container-id $TARGET_ID \
--mode readonly \
--description "Static assets for frontend container"
POST Create 1-to-1 container share
/api/v1/containers/{source_id}/storage/shares
Click "Run" to execute the request

Use when:

  • Backend sharing data with frontend
  • Database container sharing with API container
  • Specific service-to-service integration

Share directory with ALL containers in a project:

Terminal window
# Create project-wide share β€” all containers in project can access
hoody storage create --container $SOURCE_ID \
--source-path "/hoody/storage/config" \
--target-project-id $PROJECT_ID \
--mode readonly \
--description "Shared configuration for all services"
POST Create project-wide share
/api/v1/containers/{source_id}/storage/shares
Click "Run" to execute the request

Every container in project automatically mounts this share (by default).

Use when:

  • Shared configuration across all services
  • Common assets or libraries
  • Team-wide resources

{
"mode": "readonly"
}

Target containers can:

  • βœ… Read files
  • βœ… List directories
  • βœ… Check metadata
  • ❌ Cannot create files
  • ❌ Cannot modify files
  • ❌ Cannot delete files

Perfect for:

  • Static assets (images, CSS, JS)
  • Configuration files
  • Reference data
  • Logs (share read-only for monitoring)

Terminal window
# In source container
mkdir -p /hoody/storage/team-assets
# Add files
cp logo.png /hoody/storage/team-assets/
cp styles.css /hoody/storage/team-assets/

When a target container mounts a share, files appear at:

Terminal window
/hoody/shares/{share-alias}/

Example:

Terminal window
# Source creates share with alias "config"
POST /storage/shares
{
"source_path": "/hoody/storage/app-config",
"alias": "config"
}
# Target mounts share
PATCH /storage/incoming/{share_id}/mount
{"mount": true}
# Files now accessible at:
/hoody/shares/config/
β”œβ”€β”€ app.yaml
β”œβ”€β”€ database.json
└── secrets.env

The alias becomes the mount point name.


Backend shares upload directory with multiple frontends:

Terminal window
# Backend Container (source)
POST /containers/{backend_id}/storage/shares
{
"source_path": "/hoody/storage/user-uploads",
"target_project_id": "{project_id}",
"mode": "readwrite",
"alias": "uploads"
}
# Frontend Container 1 (accepts)
PATCH /containers/{frontend_1}/storage/incoming/{share_id}/mount
{"mount": true}
# Frontend Container 2 (accepts)
PATCH /containers/{frontend_2}/storage/incoming/{share_id}/mount
{"mount": true}
# Now all three containers see same /hoody/shares/uploads/
# Upload from any frontend β†’ visible to backend and other frontends

Config container shares settings with all services (readonly):

Terminal window
# Config Container
POST /containers/{config_id}/storage/shares
{
"source_path": "/hoody/storage/production-config",
"target_project_id": "{project_id}",
"mode": "readonly",
"alias": "config"
}
# All service containers mount it
# Services read from /hoody/shares/config/
# Only config container can update (others readonly)

Developers share workspace between containers:

Terminal window
# Developer A's container
POST /containers/{dev_a}/storage/shares
{
"source_path": "/home/user/project",
"target_container_id": "{dev_b_container}",
"mode": "readwrite",
"alias": "shared-project"
}
# Developer B mounts in their container
# Both edit files in real-time
# Changes sync instantly

Services share logs with monitoring container (readonly):

Terminal window
# Service 1
POST /storage/shares
{
"source_path": "/hoody/storage/service1/logs",
"target_container_id": "{monitor_container}",
"mode": "readonly"
}
# Service 2
POST /storage/shares
{
"source_path": "/hoody/storage/service2/logs",
"target_container_id": "{monitor_container}",
"mode": "readonly"
}
# Monitor container sees all logs
/hoody/shares/service1-logs/
/hoody/shares/service2-logs/

Shares progress through these statuses:

StatusDescriptionNext Steps
activeSuccessfully mounted in targetIn use
failedMount failed (see status_message)Check errors, fix, retry

Check status:

Terminal window
GET /api/v1/containers/{id}/storage/shares/{share_id}
# Response includes: "status": "active"

Source container can disable without deleting:

Terminal window
# Disable share temporarily
PATCH /api/v1/containers/{source_id}/storage/shares/{share_id}
{
"enabled": false,
"description": "Temporarily disabled for maintenance"
}
# Files unmount from target containers
# Share configuration preserved
# Re-enable later
PATCH /api/v1/containers/{source_id}/storage/shares/{share_id}
{
"enabled": true
}

Use for: Maintenance windows, testing, gradual rollouts.

Set automatic expiration:

Terminal window
POST /api/v1/containers/{id}/storage/shares
{
"source_path": "/hoody/storage/temp-files",
"target_container_id": "{target}",
"mode": "readonly",
"expires_at": 1735689600 # Unix timestamp: 2025-01-01
}
# Share auto-unmounts and notifies before expiry

Perfect for: Temporary access, demo environments, time-limited shares.


Terminal window
# Shares you created from specific container
hoody storage list --container $SOURCE_ID
# All shares you created (across all containers)
hoody storage list-all
Terminal window
# Incoming shares for specific container
hoody storage get-incoming-shares $TARGET_ID
# All incoming shares (all your containers)
hoody storage list-all-incoming
Terminal window
# Upgrade share from readonly to readwrite
hoody storage update $SOURCE_ID $SHARE_ID \
--mode readwrite --description "Now allows writes"

Target containers must remount to get updated mode.

Terminal window
# Delete share β€” unmounts from all target containers
hoody storage delete $SHARE_ID

Storage shares automatically work across different physical servers with full POSIX compliance:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Server US-West-1 β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Source Container β”‚ β”‚
β”‚ β”‚ /shared/data/ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ ↓ Hoody handles β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
↓ cross-server
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Server EU-Central-1 β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Target Container β”‚ β”‚
β”‚ β”‚ /hoody/shares/data/ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

What you get automatically:

  • βœ… Cross-server mounting - Works whether containers on same or different servers
  • βœ… Full POSIX compliance - All filesystem operations work normally
  • βœ… File locks respected - Concurrent access properly coordinated
  • βœ… Zero configuration - No setup needed for cross-server shares
  • βœ… Transparent operation - Same API whether same-server or cross-server

Share remains mounted but inaccessible.

  • Target containers see mount point: /hoody/shares/{alias}/
  • Attempting to read files: Stale file handle error
  • When source restarts: Access restored automatically

Best practice: Don’t rely on shares from containers that stop frequently.

Can I share the same directory to multiple containers?

Section titled β€œCan I share the same directory to multiple containers?”

Yes! Create multiple shares from same source_path:

Terminal window
# Share /hoody/storage/assets with 3 containers
POST /storage/shares {"source_path": "/hoody/storage/assets", "target_container_id": "A"}
POST /storage/shares {"source_path": "/hoody/storage/assets", "target_container_id": "B"}
POST /storage/shares {"source_path": "/hoody/storage/assets", "target_container_id": "C"}
# Or share once to entire project (all containers see it)
POST /storage/shares {"source_path": "/hoody/storage/assets", "target_project_id": "{project}"}

Not recommended for SQLite databases. While you CAN share /hoody/databases/ directories, it bypasses the concurrent-write safety:

Terminal window
# ❌ NOT Recommended: Sharing /hoody/databases via storage shares
POST /storage/shares
{
"source_path": "/hoody/databases",
"mode": "readwrite"
}
# Problem: Network-shared SQLite loses local-filesystem optimizations
# Better: Each container uses /hoody/databases/ locally (same-server concurrent writes)
# Better: Use hoody-sqlite HTTP API for cross-container database access

Why not recommended:

  • /hoody/databases/ concurrent-write safety is optimized for local same-server access
  • Network sharing adds latency and lock timeout risks
  • SQLite not designed for network filesystems

Better solutions:

  • Same server: Each container accesses /hoody/databases/ directly (concurrent-write-safe)
  • Cross-server: Use hoody-sqlite HTTP API to access databases remotely
  • Data sharing: Share application data directories, not database files

Share remains available but unmounted. Target can accept later:

Terminal window
# Initially reject
PATCH /storage/incoming/{share_id}/mount
{"mount": false}
# Accept later when needed
PATCH /storage/incoming/{share_id}/mount
{"mount": true}
# Files appear in /hoody/shares/{alias}/

Yes. Share configuration and mount state survive:

  • βœ… Source container restart - share remains
  • βœ… Target container restart - mount point restored
  • βœ… Both restart - everything reconnects

Yes:

Terminal window
PATCH /api/v1/containers/{source_id}/storage/shares/{share_id}
{
"alias": "new-alias"
}

Target containers must unmount and remount to use new alias. Old mount point /hoody/shares/old-alias/ becomes invalid.

Source container: Files count toward source’s storage.

Target containers: Mounted shares do NOT count toward target’s storage quota (they’re references, not copies).


Problem: Share status is "failed" with error message

Common causes:

  1. Source path doesn’t exist:

    Terminal window
    # In source container, verify path exists
    ls -la /hoody/storage/shared-path
    # Create if missing
    mkdir -p /hoody/storage/shared-path
    # Update share to retry
    PATCH /storage/shares/{id}
    {"enabled": true}
  2. Permission issues:

    Terminal window
    # Fix permissions in source container
    chown -R root:root /hoody/storage/shared-path
    chmod -R 755 /hoody/storage/shared-path
  3. Source container stopped:

    • Start source container
    • Share will automatically reactivate

Problem: Share mounted but /hoody/shares/{alias}/ is empty

Solutions:

  1. Verify share is active:

    Terminal window
    GET /api/v1/containers/{target_id}/storage/incoming
    # Check: "status": "active", "mount": true
  2. Check source container is running:

    Terminal window
    GET /api/v1/containers/{source_id}
    # Verify: "status": "running"
  3. Verify files exist in source:

    Terminal window
    # In source container
    ls /hoody/storage/shared-path
    # Should show files
  4. Unmount and remount:

    Terminal window
    PATCH /storage/incoming/{share_id}/mount
    {"mount": false}
    PATCH /storage/incoming/{share_id}/mount
    {"mount": true}

Problem: Cannot access files in /hoody/shares/{alias}/

Cause: Source container restarted while target was accessing files

Solution:

Terminal window
# Unmount and remount
PATCH /storage/incoming/{share_id}/mount
{"mount": false}
PATCH /storage/incoming/{share_id}/mount
{"mount": true}
# Or restart target container (auto-remounts)
POST /api/v1/containers/{target_id}/restart
# (Consolidated lifecycle route: POST /api/v1/containers/{id}/{operation}
# where {operation} is one of: start | stop | force-stop | restart | pause | resume)

Problem: PATCH /mount succeeds but files don’t appear

Check:

  1. Share is enabled:

    Terminal window
    GET /storage/incoming/{share_id}
    # Verify: "enabled": true
  2. Share not expired:

    Terminal window
    # Check expires_at (Unix timestamp)
    # If expired, ask source to extend or remove expiration
  3. Target container has permission:

    • Verify target is in specified project (for project-wide shares)
    • Verify target_container_id matches (for 1-to-1 shares)

Terminal window
# βœ… Good: Specific subdirectory
{"source_path": "/hoody/storage/assets"}
# ❌ Risky: Entire Hoody Kit storage
{"source_path": "/hoody/storage"}
# Sharing entire /hoody/storage exposes all service data

One share for all containers:

Terminal window
# Instead of creating 10 identical 1-to-1 shares
POST /storage/shares {"target_project_id": "{project}"}
# All containers in project can mount
# Simpler management, one configuration

Multiple writers can conflict:

Terminal window
# Container A writes /hoody/shares/data/file.txt
# Container B writes /hoody/shares/data/file.txt (same file)
# Last write wins (potential data loss)

Solution: Use application-level locking or coordinate writes (e.g., different directories per container).

Or use /hoody/databases/ for SQLite databases (automatic concurrent-write safety).

Share deletion unmounts from all targets:

Terminal window
# Snapshot source container first
POST /api/v1/containers/{source_id}/snapshots
{"alias": "before-share-deletion"}
# Then delete share
DELETE /api/v1/storage/shares/{share_id}
Terminal window
# βœ… Clear documentation
{
"description": "Read-only access to team logo, CSS, and JS assets for frontend containers. Source: /hoody/storage/static-web-assets"
}
# ❌ Vague
{
"description": "shared files"
}

Future you will thank present you when managing dozens of shares.


Storage ecosystem:

Related features:

Understanding gained:

  • βœ… Source container controls WHAT is shared
  • βœ… Target container controls IF they mount it
  • βœ… Two modes: readonly, readwrite
  • βœ… Two types: 1-to-1, project-wide
  • βœ… Works cross-server automatically (SSHFS-backed storage relay)
  • βœ… Combine with /hoody/databases/ for shared SQLite databases

Share directories between containers.
Readonly for safety. Readwrite for collaboration.

One share, multiple consumers. Data exchange without duplication.