20 days ago
On an idle service (near-zero traffic), Railway's dashboard memory metric climbs steadily over hours, then drops abruptly, then climbs again — a sawtooth pattern. Added logs that shows this is driven almost entirely by cgroup v2 file, not real application memory.
Data (from process.memoryUsage() + reading /sys/fs/cgroup/memory.current and memory.stat directly, logged every 15s):
Time | rss | anon | file | cgroup total
Fresh deploy | 63.8MB | 37.2MB | 0.0MB | 40.8MB
~20 min | 60.9MB | 38.2MB | 14.9MB | 56.7MB
~5hr | 48.2MB | 40.2MB | 65.5MB | 109.2MB
~10hr | 58.5MB | 52.3MB | 16.0MB | 72.0MB
rss/anon stay roughly flat throughout (the small anon drift is within normal heap growth); file alone accounts for nearly the entire climb, and drops sharply once the total nears ~128MB — consistent with the kernel reclaiming clean page cache under pressure. Service memory limit is set to default 8GB, so this isn't a limit-proximity issue at the container level; something else is triggering reclaim well below that. After that, the sawtooth pattern repeats.
Cross-check: reproduced on a second, unrelated service (no dependencies, zero traffic, same Railpack builder) — same climb-then-reclaim pattern, ruling out anything specific to this app's code or logging.
Questions:
- Does the dashboard "Memory" metric (and billing) use raw cgroup memory.current, or is it adjusted to exclude reclaimable file cache?
- If it's the raw figure, is this reclaimable cache actually included in usage-based billing?
- What's driving the file growth on an otherwise idle container in the first place?
Thanks!
7 Replies
20 days ago
This thread has been opened as a bounty so the community can help solve it.
Status changed to Open Railway • 20 days ago
20 days ago
- Does the dashboard "Memory" metric (and billing) use raw cgroup memory.current, or is it adjusted to exclude reclaimable file cache?
The Metric: Platform dashboards and monitoring tools typically ingest the raw container cgroup metrics (memory.current) directly from the container runtime or node exporter.
The Sawtooth Pattern: Because memory.current inherently aggregates anonymous memory + file cache + kernel memory, any accumulation of clean page cache directly inflates the metric you see on your dashboard. When the system or container runtime hits an internal watermark or pressure threshold, the kernel reclaims the file cache, causing the sharp drop in the graph.
- If it's the raw figure, is this reclaimable cache actually included in usage-based billing?
Usage-Based Impact: If a host or platform calculates billing strictly using raw continuous samples of memory.current, file cache can technically factor into the raw metric readings. However, because page cache is inherently reclaimable and drops instantly the moment other processes or containers demand RAM, it does not represent actual application memory leakage (as proven by your rss/`anon tracking staying flat).
- What's driving the file growth on an otherwise idle container in the first place?
Even with zero incoming traffic, background processes, runtimes, and logging utilities continually interact with the filesystem. The file growth is typically driven by:
Log Files & Buffers: Node.js, package managers, application logging frameworks, or system utilities writing to stdout/stderr or local log files. Even if flushed, the kernel keeps these recently accessed blocks cached in page cache (file) to speed up subsequent reads.
Runtime & Dependency Activity: Node modules, background garbage collection checks, and dynamic imports read files off the container's overlay filesystem. Every file read results in the kernel caching those disk pages into RAM as page cache, where they remain until memory pressure forces a reclaim.
20 days ago
When you said "idle" do you mean serverless ? because if not, it's a common issue with Linux Kernel. Activate the option serverless and it should stop "billing when idle"
20 days ago
Yes, exactly. When referring to "idle" in standard container hosting, it usually just means zero incoming user traffic while the process itself remains fully booted and running in the background.
Activating Railway's Serverless mode changes this behavior. When enabled, Railway monitors the container and puts it to sleep after 10 minutes of complete inactivity, cutting compute charges entirely while it's sleeping.
If you want to stop paying for those idle hours (and stop watching the page cache sawtooth climb on a container doing nothing), turning on Serverless is the exact fix:
- Open your service on Railway and go to Settings > Deploy > Serverless.
- Toggle Enable Serverless.
Keep a couple of things in mind when enabling it:
- Inactivity trigger: Railway detects activity based on outbound packets, not just inbound HTTP requests. If your app has background tasks, persistent database connection poolers, or telemetry phoning home, it will keep sending outbound data and won't sleep. You'll want to ensure database pools close idle connections so the container can actually go quiet.
- Cold boots: When a new request finally hits a slept service, the next request will experience a slight delay while the container spins back up.
19 days ago
Thank you for your answers. By the way yes, idle and serverless are two different things. I do not wish to activate that option as I want the service up all the time, but just curious as to why that's the memory behavior. It doesn't happen with every container, in fact, deploying the same app with node 22 has a different memory print and pattern.
To abidhissain12678-design: Is this information from Railway-internal docs/confirmation on other threads, or general Linux/cgroup reasoning applied here? Reference would help.
The real open question is billing specifically: is reclaimable file cache actually counted in usage-based billing, or excluded? Would appreciate a firmer yes/no, ideally from someone with visibility into the billing pipeline, possibly a Railway employee. But very grateful for your answers so far.
navarroemilioluis
Thank you for your answers. By the way yes, idle and serverless are two different things. I do not wish to activate that option as I want the service up all the time, but just curious as to why that's the memory behavior. It doesn't happen with every container, in fact, deploying the same app with node 22 has a different memory print and pattern. To abidhissain12678-design: Is this information from Railway-internal docs/confirmation on other threads, or general Linux/cgroup reasoning applied here? Reference would help. The real open question is billing specifically: is reclaimable file cache actually counted in usage-based billing, or excluded? Would appreciate a firmer yes/no, ideally from someone with visibility into the billing pipeline, possibly a Railway employee. But very grateful for your answers so far.
19 days ago
To answer your follow-up questions directly:
- Source attribution: The previous explanation regarding the page cache sawtooth pattern (
memory.currentaggregating anon, file cache, and kernel memory) is rooted in standard Linux kernel architecture and cgroup v2 behavior (specifically how memory limits, file-backed page caching, and kernel reclaim watermarks operate undermemory.stat). It is not a proprietary Railway internal document, but rather standard container runtime mechanics. - Why Node 22 behaves differently: Different Node.js versions (and their corresponding V8 engines, underlying Alpine/Debian base images, bundled dependency trees, or default GC/serialization profiles) interact with the filesystem differently. A minor shift in how modules are dynamically required, how internal telemetry/source maps are parsed, or how log buffers flush to disk will change the rate at which the kernel populates the page cache (
file). - The Billing Pipeline Question: While I cannot speak directly as an internal Railway billing engineer or provide an official contractual guarantee from deep inside their pipeline, cloud platforms using containerized infrastructure (such as those tracking resource consumption via cgroup metrics) typically bill based on the allocated service limit (e.g., your configured 8GB container ceiling or your specified replica limits) rather than micro-fluctuations in raw active usage—unless operating under strict true-up usage metrics where raw metrics can matter. However, because page cache is inherently volatile, transient, and reclaimed automatically under memory pressure, relying on platform support channels or opening a ticket directly inside Railway's Help/Central Station is the best way to get a definitive, authoritative confirmation from a platform engineer regarding how their precise metering collector samples memory for invoicing.
18 days ago
Then if you don't want to setup serverless, you should probably upgrade or downgrade the underlying config you have (some have the issue and other like node 22 seems to not have the issue)
For billing, Railway will bill anything that use memory or CPU, even if not intended, the issue you reported is continuously using a little bit of memory. As a cloud provider and PaaS they bill for usage of any kind
devsaswave
Then if you don't want to setup serverless, you should probably upgrade or downgrade the underlying config you have (some have the issue and other like node 22 seems to not have the issue) For billing, Railway will bill anything that use memory or CPU, even if not intended, the issue you reported is continuously using a little bit of memory. As a cloud provider and PaaS they bill for usage of any kind
18 days ago
Thanks for the clarification. I agree that different Node.js versions can influence page-cache behavior, which explains why Node 22 shows a different pattern.
However, I think the remaining unanswered question is whether Railway's billing pipeline charges based on raw memory.current or applies any adjustment to exclude reclaimable file cache. Since that detail isn't part of standard Linux/cgroup behavior, only Railway can confirm it.
If anyone from the Railway team could clarify how the billing collector measures memory usage, that would definitively answer the original question.
