Skip to content
Hoody.com

Ultra-fast temporary storage in RAM, enabled by default. Every container placed on a subserver has /ramdisk available (unless explicitly disabled)—perfect for hot caches, small build artifacts, and temporary processing that needs maximum speed.


Two separate reasons to reach for /ramdisk — worth keeping apart, because they call for different data:

Because it is fast

It is RAM, so I/O-bound scratch work stops waiting on storage. Anything written, read a few times, and thrown away belongs here.

Because it never touches disk

A security property, not a performance one: what you write here is never on a disk, in a snapshot, or in a backup. That is exactly what /ramdisk/secrets (private, mode 0700) exists for.

Build and test scratch — compiler and bundler intermediates, test fixtures, coverage output. Every run regenerates them, so losing them costs nothing:

Terminal window
mkdir -p /ramdisk/tmp && export TMPDIR=/ramdisk/tmp

Decrypted credentials at runtime — decrypt a key, or exchange a short-lived token, straight into /ramdisk/secrets. The plaintext exists only in memory: it is never written to disk, never captured by a snapshot, and never present on a seized drive.

Terminal window
# Plaintext lives in RAM only
(umask 077; decrypt-secret > /ramdisk/secrets/deploy.key)
trap 'rm -f /ramdisk/secrets/deploy.key' EXIT

Here, a host reboot wiping the file is a feature, not a risk — the secret cannot outlive the machine that held it.

Caches whose authoritative copy lives elsewhere — rendered fragments, thumbnails, session data. After a host reboot a cold cache is a slow request, not a lost record.

Media and data processing scratch — transcode intermediates, image-pipeline stages, sort spill files.

Database temp space for a heavy one-off query — keep the temporary b-trees out of storage:

Terminal window
mkdir -p /ramdisk/tmp
export SQLITE_TMPDIR=/ramdisk/tmp

(For Postgres, the equivalent is a temp tablespace pointed at a directory under /ramdisk.)

Handing an artifact to a sibling containernot available today. This is the one case that would justify ramdisk_scope: project, but the API does not currently accept that value on create or PATCH (see ramdisk_scope), so /ramdisk/project cannot be obtained on a new container. Use a storage share or a database in /hoody/databases/ instead.

Working recipes for these live in Perfect Use Cases below.


Container Configuration:

File Access:


Understanding /ramdisk:

Capacity: one shared pool

Per server, not per container:

  • Pool size: 512 MiB by default — a per-server value you cannot set yourself
  • Clamped to 50% of that server’s memory, so a small server’s pool is smaller
  • Read the real ceiling from GET /api/v1/containers/{id}/statsramdisk.shared_pool_maximum, or with df -h /ramdisk
  • Nothing is reserved for a container: first come, first served
  • Actual usage: Only what you store
  • Empty ramdisk = 0 bytes RAM used

On-demand allocation - RAM consumed only when files written, freed when deleted.

Speed: RAM Performance

Orders of magnitude faster than disk:

  • Read: ~10-20 GB/s
  • Write: ~10-20 GB/s
  • Latency: <1µs

vs. SSD:

  • Read: ~0.5-3 GB/s
  • Write: ~0.5-2 GB/s
  • Latency: ~50-100µs

Survives Container Restarts

Unique Hoody feature:

  • Persists through container stop/start
  • Persists through container restart
  • Cleared on host reboot — the directory tree is rebuilt EMPTY at boot

Data survives container operations, not host reboots.

Your Files Stay Private

Each container gets its own directories:

  • Container A’s /ramdisk ≠ Container B’s /ramdisk
  • /ramdisk/secrets (mode 0700) for credential material
  • /ramdisk/project exists only with ramdisk_scope: project — a value the API does not currently accept — and is shared only with your containers in that project on the same server

Capacity is shared even where the files are not.

Memory, Not Disk

Charged to your server’s memory:

  • Counts against RAM; contributes to no disk total
  • Mounted noswap — the kernel cannot page these pages out
  • Which is why the pool is capped conservatively: everything you store is RAM your own processes can no longer use

Three paths, depending on scope:

PathWho can read/write itNotes
/ramdiskThis container onlyYour general-purpose scratch space
/ramdisk/secretsThis container only, mode 0700The designated place for credential material — only the container’s own root can open it
/ramdisk/projectYour containers in this project on the same serverPresent only when ramdisk_scope is project — a value the API does not currently accept

ramdisk_scope is container (the default) or project — but project is not currently accepted from callers, so container is the only value you can set today.

Today, /ramdisk and /ramdisk/secrets are private to each container. New containers cannot obtain /ramdisk/project, although containers that already hold ramdisk_scope: project may still have it.

Terminal window
# Refused today with 400
PATCH /api/v1/containers/{id}
{"ramdisk_scope": "project"}

Rules enforced today for containers that already hold project:

  • A RAM disk cannot span servers. project means same project and same server. Containers of one project placed on different servers each get their own, non-shared /ramdisk/project.
  • ramdisk_scope must be container when ramdisk is false — a shared scope with no ramdisk is ambiguous and is rejected.
  • Narrowing (projectcontainer) is rejected while the container is running; stop it first so the shared mount can be verifiably removed before the change is recorded.

When project is re-enabled, widening (containerproject) will work on a running container.


Every container on a subserver automatically has /ramdisk available unless explicitly disabled.

Terminal window
# Create container — ramdisk enabled by default
hoody containers create --project $PROJECT_ID --server-id $SERVER_ID --name "my-container" --hoody-kit
# Create container with ramdisk explicitly disabled
hoody containers create --project $PROJECT_ID --server-id $SERVER_ID --name "no-ramdisk" --hoody-kit --no-ramdisk
POST Create container with ramdisk enabled (default behavior)
/api/v1/projects/{project_id}/containers
Click "Run" to execute the request

/ramdisk is available immediately but consuming ZERO RAM (empty = no allocation).

Check ramdisk status:

Terminal window
GET /api/v1/containers/{id}
# Response: "ramdisk": true (enabled) or false (disabled)

Access like any directory:

Terminal window
# In container (via terminal or SSH)
cd /ramdisk
# Create directories
mkdir -p /ramdisk/cache
mkdir -p /ramdisk/builds
# Write files (ultra-fast)
echo "data" > /ramdisk/cache/session-abc.json
# Read files (ultra-fast)
cat /ramdisk/cache/session-abc.json
# Credentials go in the 0700 directory
(umask 077; printf '%s' "$API_KEY" > /ramdisk/secrets/api.key)
# YOUR OWN footprint
du -sh /ramdisk
# THE POOL — size and used are server-wide, not this container's
df -h /ramdisk

Files in /ramdisk are stored in RAM - no disk I/O.


Terminal window
# Put the CACHE in ramdisk — not node_modules, which rarely fits in 512 MiB
export NPM_CONFIG_CACHE=/ramdisk/npm-cache
cd /home/user/project
npm install # Tarball cache reads/writes stay in RAM
# Then copy final artifacts to persistent storage
cp -r dist /hoody/storage/production/

Speed boost: cache-heavy installs get much faster — as long as what you put in /ramdisk fits the pool.

Terminal window
# Application cache in RAM
mkdir -p /ramdisk/app-cache
# Store frequently accessed data (a SMALL database — the pool is 512 MiB)
cp /hoody/databases/users.db /ramdisk/app-cache/
sqlite3 /ramdisk/app-cache/users.db "SELECT ..." # Ultra-fast
# Session storage
echo '{"user": 1, "token": "abc"}' > /ramdisk/sessions/user-1.json

Response time: <1ms for cache hits.

Process files without disk I/O (keep each chunk well under the 512 MiB pool):

Terminal window
# Download a dataset CHUNK to ramdisk
curl "https://data.example.com/dataset.csv" > /ramdisk/dataset.csv
# Process in RAM (no disk writes)
awk -F',' '{sum+=$3} END {print sum}' /ramdisk/dataset.csv > /ramdisk/result.txt
# Upload the result, then free the pool immediately
curl -X POST "https://api.example.com/results" \
-d "@/ramdisk/result.txt"
rm -f /ramdisk/dataset.csv /ramdisk/result.txt

No disk wear from temporary files.

Work in batches — a full frame dump will overflow a 512 MiB pool long before the video ends:

Terminal window
# Extract a WINDOW of frames to ramdisk (burst I/O)
ffmpeg -ss 00:00:10 -t 5 -i video.mp4 /ramdisk/frames/frame_%04d.png
# Process frames (parallel reads - ultra-fast)
for frame in /ramdisk/frames/*.png; do
convert $frame -resize 50% $frame
done
# Merge back to video
ffmpeg -i /ramdisk/frames/frame_%04d.png output.mp4

Thousands of small file operations benefit massively from RAM speed.


CRITICAL: one pool, 512 MiB by default, shared by all of your containers on that server.

There is no per-container ramdisk quota to plan. Your server gets one tmpfs pool, and every container of yours on that server draws from it:

Your server:
- Pool size: 512 MiB by default — a per-server value, not a per-container one
- Hard ceiling: 50% of that SERVER's memory — the configured size is clamped to it,
so a small server's pool is SMALLER than 512 MiB
- Reserved per container: NOTHING — first come, first served
- Empty ramdisk: 0 bytes of RAM consumed

Critical distinction: CAPACITY ≠ allocation. RAM is consumed on demand and freed the moment files are deleted.

Because nothing is reserved, one container can consume the whole pool:

Terminal window
# Example for a server whose reported pool ceiling is 512 MiB.
Container A writes 500 MiB to /ramdisk ~12 MiB left for everyone else
Container B tries to write 50 MiB "No space left on device"

When the pool is full:

  • Writes fail immediately with ENOSPC — nothing silently degrades to disk
  • Containers keep running; only the write fails
  • Deleting files in any container on that server frees the space again

There is no swap fallback. The pool is mounted noswap, so these pages can never be paged out. That is deliberate — RAM disk contents stay in RAM — but it means the space you occupy is space your own processes cannot have.

Example planning:

Terminal window
# Example for a server whose reported pool ceiling is 512 MiB.
# Scenario A: One build container (comfortable)
# package cache in /ramdisk: ~200 MiB, cleared after each build
# Scenario B: Four small services (comfortable)
# each keeps ~50 MiB of hot cache = ~200 MiB total
# Scenario C: Tight
# two containers each holding 240 MiB — the pool is effectively full,
# and a third container has nowhere to write

Monitor your own footprint with du -sh /ramdisk; use df -h /ramdisk (or the stats endpoint) to see how much of the shared pool is left.

From the API — measured, per scope:

Terminal window
GET /api/v1/containers/{id}/stats
# The ramdisk field sits beside `memory` (it is memory, never disk):
# "ramdisk": {
# "scope": "container",
# "shared_pool_maximum": 536870912, # the SHARED ceiling for this server; null if unconfirmed
# "capacity_reserved": false, # always false: nothing is held for you
# "usage": { "private": 4096, "secrets": 0 }
# }
  • shared_pool_maximum is the whole pool, which co-tenant containers of yours also draw from — it is not your quota, so do not turn it into a percentage.
  • usage is null on the container list endpoint (measuring costs a host round trip per container). That means “open the container to measure”, not “empty”.
  • With scope: project, usage.project is the shared directory’s size — it is shared with sibling containers, so adding it to private double-counts.

From inside the container:

Terminal window
du -sh /ramdisk # what THIS container is holding
df -h /ramdisk # the shared pool: total size and how much is left

If the pool is close to full:

  1. Delete finished work: rm -rf /ramdisk/build
  2. Disable ramdisk on containers that never use it
  3. Move anything larger than a working set to container storage

Terminal window
POST /api/v1/containers/{id}/{operation} # operation=restart

PERSISTS

  • All files in /ramdisk remain
  • Directory structure intact
  • No data loss

Unique to Hoody: Traditional ramdisks clear on reboot. Hoody’s /ramdisk persists through container operations.


Try ramdisk first, fall back to disk:

import os
def get_cached_data(key):
ramdisk_path = f'/ramdisk/cache/{key}.json'
disk_path = f'/hoody/storage/cache/{key}.json'
# Try ramdisk first (fast)
if os.path.exists(ramdisk_path):
return read_file(ramdisk_path)
# Fall back to disk
if os.path.exists(disk_path):
data = read_file(disk_path)
# Promote to ramdisk for next access
write_file(ramdisk_path, data)
return data
# Cache miss
return None

Build in ramdisk, save final output to disk:

#!/bin/bash
# Build script — keep the intermediate tree inside the 512 MiB pool
# Compile in ramdisk (fast)
cd /ramdisk/build
cmake ..
make -j$(nproc)
# Test binary (fast startup from RAM)
./test-suite
# Copy ONLY final binary to persistent storage
cp binary /hoody/storage/production/app-v1.2.3
# Free the pool for your other containers as soon as you are done
rm -rf /ramdisk/build

Store sessions in RAM for speed + auto-expiry:

// Sessions in ramdisk (fast read/write)
const sessionPath = `/ramdisk/sessions/${sessionId}.json`;
// Write session
fs.writeFileSync(sessionPath, JSON.stringify({userId, token, expiresAt}));
// Read session (ultra-fast)
const session = JSON.parse(fs.readFileSync(sessionPath));
// Host reboot = automatic session cleanup (no stale sessions)

Actual speed comparison:

Writing a 256 MiB file (a 1 GB file does not fit the 512 MiB pool):

StorageWrite SpeedTime
/ramdisk~15 GB/s~0.02s
SSD~2 GB/s~0.13s
HDD~200 MB/s~1.3s

RAM is 7-70x faster.


1. ramdisk is Enabled by Default (Disable if Not Needed)

Section titled “1. ramdisk is Enabled by Default (Disable if Not Needed)”

Ramdisk is enabled automatically, but you can opt out at creation time:

Terminal window
# Disable ramdisk when creating the container
POST /api/v1/projects/{id}/containers
{
"ramdisk": false // Explicitly disable at creation
}

When to disable:

  • Simple APIs (CRUD operations, no heavy I/O)
  • Static file servers
  • Long-running daemons with minimal disk access
  • Containers that would only compete for a pool their siblings need

When to keep enabled (default):

  • Build servers (compilation, npm install)
  • Cache servers (Redis-like workloads)
  • Media processing (video/image transcoding)
  • Data processing (ETL, analytics)

Remember: Enabled ramdisk with NO files = zero RAM consumed. Only disable if you’re CERTAIN container won’t benefit.

Never rely on /ramdisk for critical data:

Terminal window
# Good: Temporary processing
wget https://example.com/dataset.zip -O /ramdisk/dataset.zip
unzip /ramdisk/dataset.zip -d /ramdisk/processing/
# Process and save results to /hoody/storage
# Bad: Long-term storage
cp important-data.db /ramdisk/ # Lost on host reboot!

Rule: If data matters after host reboot, don’t put it ONLY in /ramdisk.

The pool is shared and its ceiling is fixed per server (512 MiB by default, clamped to 50% of server memory) — clean up the moment a task finishes:

#!/bin/bash
# Build script with cleanup
# Build in ramdisk
npm install --prefix /ramdisk/build
npm run build --prefix /ramdisk/build
# Copy final bundle
cp /ramdisk/build/dist/*.js /hoody/storage/production/
# Clean up immediately (free RAM)
rm -rf /ramdisk/build
# Or clean on exit
trap 'rm -rf /ramdisk/build' EXIT
Terminal window
# The SHARED pool — how full is it for everyone on this server?
df -h /ramdisk
# Alert if the pool is >80% full
USAGE=$(df /ramdisk | awk 'NR==2 {print $5}' | sed 's/%//')
if [ $USAGE -gt 80 ]; then
echo "WARNING: shared ramdisk pool >80% full"
fi
# YOUR OWN share of it
du -sh /ramdisk

Integrate with hoody-notifications for alerts.

If your app requires ramdisk, say so in your README:

## Runtime requirements
- `ramdisk: true` (the default). Frame extraction writes ~200 MiB of PNGs to
`/ramdisk/frames` in batches, then deletes them. Remember the pool is
shared with our other containers on this server — check its real ceiling
with `df -h /ramdisk` (512 MiB by default).

Future maintainers know why ramdisk is enabled — and what it costs the pool.


Yes. Dramatically faster:

  • RAM: ~15 GB/s throughput, <1µs latency
  • SSD: ~2 GB/s throughput, ~50-100µs latency
  • 10-50x faster for I/O-intensive workloads

512 MiB by default — for the whole pool, shared by your containers on that server. It is not a per-container allowance. It is a per-server value, and whatever is configured is clamped to 50% of that server’s memory, so a small server’s pool is smaller than 512 MiB. The authoritative figure for your container is ramdisk.shared_pool_maximum on GET /api/v1/containers/{id}/stats (bytes, or null when no ceiling is confirmed) — or df -h /ramdisk from inside.

Actual RAM consumption = only what is stored:

Terminal window
# Example for a server whose reported pool ceiling is 512 MiB.
df -h /ramdisk
# Filesystem Size Used Avail Use% Mounted on
# tmpfs 512M 120M 392M 24% /ramdisk
# ^^^^ ^^^^ ---- POOL capacity vs POOL usage
# Pool Used by ALL your containers on this server

An empty pool shows its full size but consumes 0 bytes of RAM — memory is allocated on demand. For this container’s own footprint, use du -sh /ramdisk.

Not through the container API. The size is a per-server setting: there is no size parameter on container create or PATCH, no dashboard control, and no per-container override — and it can never exceed 50% of that server’s memory. If your workload needs more room, stage it on container storage and keep only the hot working set in /ramdisk.

Why does data persist through container restart but not host reboot?

Section titled “Why does data persist through container restart but not host reboot?”

Container restart:

  • Container stops → the server keeps the pool mounted → Container starts → Same RAM data

Host reboot:

  • Host powers off → All RAM cleared → Host powers on → the pool is recreated and the directory tree is rebuilt empty

Physical limitation of RAM - power loss = data loss.

Can I disable ramdisk after creating container?

Section titled “Can I disable ramdisk after creating container?”

Yes:

Terminal window
# Stop container
POST /api/v1/containers/{id}/{operation} # operation=stop
# Disable ramdisk
PATCH /api/v1/containers/{id}
{"ramdisk": false}
# Start container
POST /api/v1/containers/{id}/{operation} # operation=start
# operation enum: start | stop | force-stop | restart | pause | resume
# /ramdisk no longer available (RAM freed)

WARNING: Any data in /ramdisk is lost when disabling.

Same as any filesystem:

  • “No space left on device” errors
  • Applications fail to write
  • Nothing spills over to disk, and nothing is swapped out — the write simply fails

Remember it is one pool: a sibling container of yours on the same server can fill it, and freeing space in any of them helps all of them.

Solution:

Terminal window
# Delete old files
rm -rf /ramdisk/old-cache/*
# Or clear everything in THIS container
rm -rf /ramdisk/*
# See how much of the pool is left
df -h /ramdisk

Not on anything you create today. Sharing needs ramdisk_scope: project, and the API refuses that value on both create and PATCH (400, “ramdisk_scope: project is temporarily unavailable”), so a new container cannot be given a shared /ramdisk/project. Containers that already hold the scope keep it.

And when it is re-enabled, these still hold:

  • /ramdisk and /ramdisk/secrets are always private to a single container
  • A RAM disk cannot span servers — containers of the same project on different servers get separate, non-shared /ramdisk/project directories
  • It cannot be shared through storage shares

Workaround for anything wider:

Terminal window
# Copy from ramdisk to persistent storage
cp /ramdisk/data.json /hoody/storage/shared/
# Share persistent storage instead
POST /api/v1/containers/{id}/storage/shares {"source_path": "/hoody/storage/shared", "target_container_id": "TARGET_CONTAINER_ID", "mode": "readwrite"}

Or use shared concurrent-write database in /hoody/databases/.


Problem: /ramdisk directory doesn’t exist

Solutions:

  1. Verify ramdisk enabled:

    Terminal window
    GET /api/v1/containers/{id}
    # Check: "ramdisk": true
  2. If false, enable it:

    Terminal window
    POST /api/v1/containers/{id}/{operation} # operation=stop
    PATCH /api/v1/containers/{id} {"ramdisk": true}
    POST /api/v1/containers/{id}/{operation} # operation=start
    # operation enum: start | stop | force-stop | restart | pause | resume
  3. Restart container if status shows true but missing:

    Terminal window
    POST /api/v1/containers/{id}/{operation} # operation=restart
  4. Check the container is on a subserver. A container that is not placed on a subserver has no pool to attach and therefore no /ramdisk. GET /api/v1/containers/{id}/stats omits the ramdisk field entirely in that case.

Problem: /ramdisk/project does not exist

Cause: /ramdisk/project only exists when ramdisk_scope is project, and that scope cannot be set today — the API refuses it on both create and PATCH:

Terminal window
GET /api/v1/containers/{id}/stats
# "ramdisk": { "scope": "container", ... } ← no /ramdisk/project
PATCH /api/v1/containers/{id} {"ramdisk_scope": "project"}
# 400 — `ramdisk_scope: project` is temporarily unavailable

Nothing about your project changes that: the refusal is unconditional, not a reaction to the project’s members. Move the data with a storage share or /hoody/databases/ instead.

If the container already holds scope: project and the directory is still missing, check the server: a RAM disk cannot span servers. Containers of the same project on different servers each get their own /ramdisk/project, and they do not see each other’s files.

Problem: Writes to /ramdisk fail even though the container has free memory

Cause: The shared pool is full — very often filled by one of your other containers on that server.

Debug:

Terminal window
df -h /ramdisk # pool: Size / Used / Avail across ALL your containers here
du -sh /ramdisk # what THIS container is contributing

Solutions:

  1. Immediate: Delete finished work — in this container or any sibling on that server

    Terminal window
    rm -rf /ramdisk/build /ramdisk/old-cache
  2. Long-term: Disable ramdisk on containers that never use it

    Terminal window
    PATCH /api/v1/containers/{id} {"ramdisk": false}
  3. Structural: Move anything bigger than a working set to container storage. The pool cannot be enlarged.

Problem: Files existed yesterday, now missing

Likely causes:

  • The host server rebooted — the pool is recreated empty at boot
  • With ramdisk_scope: project, one of your sibling containers deleted them from the shared /ramdisk/project

Remember: /ramdisk is cleared on host reboot (not container reboot).

Prevention:

  • Never store critical data ONLY in /ramdisk
  • Always copy important results to persistent storage
  • Document ramdisk as temporary storage in your app

Storage ecosystem:

Performance tuning:

Understanding gained:

  • /ramdisk enabled by default (set ramdisk: false to disable); no subserver means no /ramdisk
  • RAM consumed on-demand (empty ramdisk = 0 bytes used)
  • Capacity is one shared pool per server — 512 MiB by default, not something you can set, clamped to 50% of that server’s memory; nothing is reserved per container
  • It is memory, not disk — charged to your server’s RAM, never paged out (noswap)
  • /ramdisk and /ramdisk/secrets (mode 0700) are private; /ramdisk/project appears only with ramdisk_scope: project — a value the API does not currently accept
  • Provides RAM-speed storage (10-50x faster than SSD)
  • Persists through container restarts (unique Hoody feature!)
  • Cleared on host reboot — the tree is rebuilt empty (RAM = power loss = data loss)
  • Watch du -sh /ramdisk for your footprint and df -h /ramdisk for what is left of the pool

Ultra-fast RAM storage, enabled by default. One shared pool per server, 512 MiB by default. Survives container restart. Cleared on host reboot.

Budget against the shared pool. Clean up early. Use for speed, not persistence.