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 is reflected in the mount point name. The exact mount path is determined by Hoody’s infrastructure and cannot be set directly by the caller.


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/

A share reports one of 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 list incoming --container $TARGET_ID
# All incoming shares (all your containers)
hoody storage list-all incoming
Terminal window
# Upgrade share from readonly to readwrite
hoody storage update --container $SOURCE_ID --share-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 --yes

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
  • βœ… 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.