惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Attack and Defense Labs
Attack and Defense Labs
V
Visual Studio Blog
云风的 BLOG
云风的 BLOG
爱范儿
爱范儿
Hugging Face - Blog
Hugging Face - Blog
GbyAI
GbyAI
有赞技术团队
有赞技术团队
J
Java Code Geeks
小众软件
小众软件
WordPress大学
WordPress大学
T
The Blog of Author Tim Ferriss
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
酷 壳 – CoolShell
酷 壳 – CoolShell
B
Blog
U
Unit 42
大猫的无限游戏
大猫的无限游戏
G
Google Developers Blog
I
InfoQ
Engineering at Meta
Engineering at Meta
F
Fortinet All Blogs
IT之家
IT之家
博客园 - Franky
腾讯CDC
罗磊的独立博客
雷峰网
雷峰网
M
MIT News - Artificial intelligence
博客园 - 司徒正美
A
About on SuperTechFans
SecWiki News
SecWiki News
Project Zero
Project Zero
T
Tenable Blog
The Last Watchdog
The Last Watchdog
Security Latest
Security Latest
Google DeepMind News
Google DeepMind News
C
Cyber Attacks, Cyber Crime and Cyber Security
PCI Perspectives
PCI Perspectives
博客园 - 【当耐特】
C
Check Point Blog
F
Full Disclosure
MongoDB | Blog
MongoDB | Blog
H
Help Net Security
Google Online Security Blog
Google Online Security Blog
T
Tor Project blog
T
Threat Research - Cisco Blogs
AI
AI
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Application and Cybersecurity Blog
Application and Cybersecurity Blog
美团技术团队
Spread Privacy
Spread Privacy

Railway Blog

Where Railway is, and where it's going (Summer 2026) PaaS vs IaaS vs SaaS: What Each Means and Who Should Pick What in 2026 The Best Continuous Deployment Tools in 2026 The Best PaaS for Multi-Region Deployments in 2026 The Best Platforms for Monorepo Deployments in 2026 Compliance Isn't a Feature, It's a Posture What is BYOC (Bring Your Own Cloud)? A Developer's Guide for 2026 The Best Managed Kubernetes Hosting in 2026 The Best Container Registries in 2026 The Vanilla Cloud Tax: What Rolling Your Own on AWS Actually Costs What is a PaaS? A Developer's Guide for 2026 The Best Cloud Observability and Logging Tools in 2026 The Best PostgreSQL Hosting for Developers in 2026 The Best Multi-Region Hosting Platforms in 2026 The Best Platforms to Deploy AI Apps in 2026 (Not the Models, the Apps Around Them) The Agent-Native Cloud: What It Means and Why It Matters Incident Report: May 19, 2026- GCP Account Suspension Counting to 3 with a new builder processing 50M+ monthly builds Railway iOS preview now available via TestFlight Kill your onboarding: selling to 10,000+ new users a day Your AI wants to nuke your database. Guardrails fix that. Better Rails for Agents: A New Remote MCP and Railway Agent in the CLI Moving Railway's Frontend Off Next.js One command deploys, there's a Stripe APP for that From registrar to deployed: buying a domain inside Railway A letter to open source builders who deserve more Networking is a black box, we used eBPF to open it Heroku Walked So Railway Can Run Security Features Your Security Team Will Love Railway Runs Open Source, Now We're Funding It Railway raises $100M Series B to unburden the builders Deploy autoscaling services, AI Workflow automation, and LLM APIs Without Kubernetes Hosting Postgres with GeoLite2: a practical guide to IP geolocation, data loading, and updates Serverless functions vs containers: CI/CD, database connections, cron jobs, and long-running tasks Hosting Postgres with pgvector: provider tradeoffs, migrations, indexes, and tuning Introducing the Railway integration on Delve.co Secure Cloud Hosting for Compliance: A Practical Guide for Startups and Regulated Industries How G2X Unlocked Rapid Experimentation at Scale with Railway MindFort Runs 100+ AI Pen Testing Agents Without Their Previous $10k AWS Bill How Bilt's Marketing Engineering Team Delivers at Scale with Railway Railway Technology Partners: Earn Revenue on Templates You Didn't Build ~$1 Million Paid to Developers Who Built Railway Templates CI/CD for Modern Deployment: From Manual Deploys to PR Environments Kernel Powers 1,000+ AI Agents on $444/Month of Railway Infrastructure Deploy Full-Stack TypeScript Apps: Architectures, Execution Models, and Deployment Choices Railway vs Cloudflare: How Their Architectures Differ and When to Use Each Run Scheduled and Recurring Tasks with Cron Monitoring & Observability: Using Logs, Metrics, Traces, and Alerts to Understand System Failures Logs, Metrics, and Traces: What Does Each Signal Tell You? Server rendering benchmarks: Railway vs Cloudflare vs Vercel Top five Heroku alternatives Comparing top PaaS and deployment providers Pricing to Encourage Use The F in SOC2 stands for functional Deploy Together, Earn Together: Introducing Railway Partnerships How We Oops-Proofed Infrastructure Deletion on Railway Bring Back the Free Plan Railway MCP - Stateful, Serverful, Pay-per-use Infrastructure Hackathon: Winners Announced! Mark Your Calendar: Railway User Hackathon with Prizes Launching Railway's Affiliate Program Zero-Touch Bare Metal at Scale Ssh, We’re Announcing One More Thing! $1M for Open Source Introducing Central Station Speed Isn’t Just About Code, It’s About Where That Code Runs One-Second Deploys? We Didn’t Believe It Either Why We’re Moving on From Nix Railway V3: Faster and Cheaper How to Migrate from Cloudflare Pages to Railway Supercharging Directus on Railway with a Static Frontend How to Migrate from AWS Lambda to Railway Deploy Triton Inference Server on Railway How to Handle Database Connection Pooling Building a NestJS App on Railway Manually Optimize Deployments on Railway Implement a GitHub Actions Testing Suite Building a SaaS application on Railway Deploy a Dart App on Railway, Part 2 Deploy a Dart App on Railway, Part 1 Implementing Feature Flags from Scratch Cron Jobs with Django and GitHub Actions Deploy Offen on Railway Queues on Railway Working with NX, Railway and CI/CD Automated PostgreSQL Backups Using GitLab CI/CD with Railway Migrating From Heroku To Railway Cron Jobs on Railway Deploy Beam on Railway Deploy Authorizer on Railway Deploying Monorepo Applications How to Backup and Restore Your Postgres Database How to Backup Your Redis Instance Deploy Cusdis on Railway Deploy Ghost on Railway Using Github Actions with Railway Deploy Calendso (cal.com) on Railway Self-hosted website analytics Use Notion as a CMS for your NextJS blog
Scaling a SaaS application on Railway
Anshuman Bhardwaj · 2024-12-13 · via Railway Blog

In the previous tutorial, you built a job board SaaS application using Remix, PostgreSQL, and Railway. You also deployed it to the internet with a custom domain and Cloudflare proxy. In this article, you’ll learn to scale the SaaS to handle high traffic, improve performance, and tackle some of the challenges that come with design choices. You’ll also learn about various techniques to save cost of running your SaaS application, while keeping the user experience on par.

Continuous deployment

Continuous deployment is an automated process in which code changes are tested, verified, and automatically pushed to the live environment. This ensures that updates or new features are continuously delivered to users without manual intervention, speeding up the development cycle.

Railway automatically deploys the latest commits to the main branch of the connected GitHub repository. But as your application grows and you ship more features, you need to ensure that the features are tested on a live environment before serving the customers to ensure they work properly outside your development machine.

To solve this problem, you can use the Railway environments feature to create an isolated environment called Staging for your project that you can manage without affecting services in the production environment. You can link the Staging environment to the stage branch. All the new features are first merged into the stage branch and tested on the staging environment before serving the customer, as shown in the following diagram.

Deployment pipeline in Railway
Deployment pipeline in Railway

To implement this solution, follow these steps:

  • In your Git project, create a new branch named stage from the main branch.
  • Push the stage branch to GitHub.
  • In your Railway dashboard, go to your project page.
  • Click production > New Environment: New Environment dialog opens.
Creating a new environment in Railway
Creating a new environment in Railway
  • In the Name field, enter staging.
  • Select Duplicate Environment.
  • Click Create Environment.
  • Click Deploy.

This creates a new staging environment and sets up the same services as the production environment.

You’ll notice that Railway has automatically imported the environment variables from the production environment and replaced the DATABASE_URL with the database URL of the PostgreSQL instance of the staging environment. Railway has also assigned a public domain name to this environment and similar to the production environment you can also add a custom domain to it.

Now in the staging environment

  • Go to job-board > Settings > Source > Branch connected to staging and select stage branch.
Updating the branch in staging
Updating the branch in staging

Railway will automatically deploy your application for every new commit on the connected branch and you don’t have to worry about it because Railway performs zero downtime deployments, which means that the previous version of the application is kept running until the new version passes the health checks. If something goes wrong in a new deployment, you can also perform a one-click rollback to any previously deployed version of the application from the Deployments section.

Handle high traffic

For any new SaaS product, it’s hard to calculate how many resources are required to serve the customers because the traffic patterns are unpredictable. The easiest solution to tackle this is to over-allocate resources, while it is rarely the best decision when you’re not making money off the product.

There are two ways to scale your application deployment:

  1. Vertically: by adding more resources to a single machine.
  2. Horizontally: by adding more machines that handle requests independently.

Railway supports both approaches and even mixes them up quite well for the best experience.

Vertical scaling

Railway auto-scales your application resources based on traffic and consumption. This is helpful for both upscaling to handle as many requests as you want and to downscaling when there is not many users for the application. This is all done automatically and you can check the resource usage metrics from job-board > Metrics tab to see the historical usage patterns for up to 30 days.

Horizontal scaling

With Railway you can add replicas to your service and distribute the incoming request load between multiple instances. Replicas are also auto-scaled vertically giving it the best of both worlds. Because the job board application does file upload processing which is a long-running task it is a good idea to have multiple instances of the application running.

To add the replica to the production environment -

  • Go to job-board > Settings > Replicas.

Here you can increase the count to any number based on your requirement.

Adding replicas to the Job Board service
Adding replicas to the Job Board service

You’ll notice that Railway doesn’t let you add replicas just yet because the job-board service is using a persistent volume. To tackle this issue, you need to decouple the storage from the job-board service by adding an external storage to your service.

Global distribution

To improve application performance and user experience of your application, you can also choose a deployment region closer to your primary customers. With Railway you can do so from the job-board > Settings > Region settings.

You can also use global CDN networks such as Cloudflare or AWS Cloudfront to serve static content faster. More on this in the next section.

Cost management

When starting a SaaS business, it’s important to regularly gauge the cost of running the application so that you can optimize the code or architecture choices to better use the resources available and keep the cost to a minimum. Railway provides many features out-of-the-box to reduce cost of running your application.

Cache static content on using Cloudflare

It’s a good practice to cache the static content or public content that changes seldom on the CDN level. By doing so, you reduce the number of requests to your origin server (Railway) and in turn, reduce the resource consumption and load.

The job details page in this project is a good example of such optimization. Because the job details are supposed to be changed seldom and this gives you the opportunity to leverage HTTP caching.

Remix lets your return route level headers that you can use to add the Cache-Control HTTP header for client-side and CDN level caching.

  • Add the following code snippet to the app/routes/jobs.$jobId.tsx file. This will cache the job details pages for 3600 seconds or 1 hour.
export const headers: HeadersFunction = () => {
  return {
    "Cache-Control": "public, max-age=3600, s-maxage=3600", // cache for 1 hour
  };
};

Because you’ve not implemented cache purge on-page content changes, it’s important to inform your customers about the caching behavior to avoid confusion when they edit the page.

After the application is deployed, visit the page to confirm if the caching is applied using the browser dev tools.

Observing caching behavior in DevTools
Observing caching behavior in DevTools

You’ll notice that the response time is still quite high due to latency between the us-west region and India. You’ll also see that even though the cache-control header is returned in the response, Cloudflare didn’t utilize it. This is because you need to set up caching rules on the CDN level to activate the cache control header usage. This project is using Cloudflare proxy network but the same steps will apply to other CDNs as well.

To set up the cache rule in Cloudflare, follow these steps:

  • Open your Cloudflare dashboard, go to Site > Caching > Cache rules.
  • Click Create rule.
  • In the Name field, enter cache job details pages.
  • In If incoming requests match… section, select Custom filter expression.
    • For Field, select URI Full.
    • For Operator, select wildcard.
    • For Value, enter https://YOUR_APP_DOMAIN_NAME/jobs/* because you only want this rule to apply to the job details page.
  • In Cache eligibility, select Eligible for cache.
  • In Edge TTL, select Use cache-control header if present, bypass cache if not. To cache the page at the CDN level.
  • In Browser TTL, select Respect origin TTL. To cache the page in the user’s browser.
  • Click Save.

After a few seconds, try to reload the page a few times and you’ll notice that the response is cached and response time also is much lower. You can confirm the cache hit status with the cf-cache-status response header.

Observe new cache behavior in DevTools
Observe new cache behavior in DevTools

Save cost on Railway

Railway automatically handles scaling up and down for you, which means you’re never paying more than what your application is using. But there are ways in which you can reduce your costs even more. For example:

  • App sleeping: Railway will stop the container after a period of no traffic on your service and when the traffic resumes, the application is restarted automatically. This is a good way to reduce the cost of your secondary environment, in this case, staging, because it is only used to test changes and not by the customers.
  • Reduce egress: It’s also a good idea to use private networking between services to avoid extra egress fees. When using distributed storage services, you should use pre-signed Get object URLs instead of downloading and returning the file from the Railway app to avoid double-egress fees: once from the storage provider and then by Railway.

Add external storage for horizontal scaling

To tackle this issue, you can use a distributed storage service such as AWS S3 or Cloudflare R2, but they add up to the cost because of the egress fees. You can instead use an open-source alternative such as MinIO, which will also not incur any egress fees because you can deploy it within your Railway project. You can follow along this tutorial using this GitHub repository.

To create a MinIO instance in your Railway project, follow these steps:

  • Open the project page in your Railway dashboard.
  • Click Create.
  • Click Template.
  • Search and select MinIO.

This will add a MinIO service group with the console and bucket to your project. Click on Console and open the console URL in a new browser tab.

Locating the MinIO console URL
Locating the MinIO console URL

On the MinIO Console login page,

  • In the username field, enter the value of the USERNAME variable from the Console service.
  • In the password field, enter the value of the PASSWORD variable from the Console service.

This will open the MinIO console for you.

  • In the left navigation menu, click Buckets and then click Create Bucket.
  • Create a bucket called job-board-prod for the production environment and another one called job-board-dev to use for local development.

For brevity, this tutorial uses the production environment instance of the MinIO for development but you should set it up locally as well.

MinIO Console
MinIO Console
  • Now go to the Access Keys in the MinIO Console and click Create Access Key to create a new key.
  • Copy the credentials and save them in the .env file of your local project as follows:
MINIO_ACCESS_KEY=<paste-the-value-here>
MINIO_SECRET_KEY=<paste-the-value-here>
MINIO_BUCKET=job-board-dev

It’s recommended to apply strict access rules when creating access keys. To learn more about Policy-Based Access Control (PBAC), see Access Management.

Now go to your Railway project page

  • Select MinIO Bucket service.
  • From the Variables tab, copy the value of the MINIO_PUBLIC_ENDPOINT variable and add it to your local .env file.

You need to use the public endpoint only to access outside of the Railway network.

MINIO_ENDPOINT=<paste-the-value-here>

MinIO is S3 compatible so you can use it directly with the AWS S3 clients in your application.

  • Run the following command in the local project to install the AWS S3 Typescript client
npm i @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
  • Update the app/routes/jobs.$jobId.tsx file to configure the S3 client,
  • Upload the file to MinIO and delete the uploaded file from the server disk.
  • Update the resume download code in the app/routes/dashboard.$jobId.$applicantId.resume.tsx file, to return a pre-signed URL of the file from MinIO instead of returning it from the local disk.
  • Merge the code to the staging branch.
  • Add the MinIO service to the staging environment on Railway.
  • Create a new bucket called job-board-stage.
  • Add the MinIO credentials to the service environment variables.
  • Create a new access key for the staging environment and update the BUCKET_NAME with job-board-stage.
  • Test the application on staging and merge the staging branch into the main branch.
  • Update the MinIO credentials on the production environment and set the BUCKET_NAME with job-board-prod .

After the deployment finishes your application can now work without persistent volumes, which means you can now add more replicas to your service and horizontally scale the SaaS application.

To remove the volume, right-click it and select Delete volume. Confirm the deletion in the next step.

Now go to job-board > Settings > Replicas, update the replicas count to 4 and save the changes. You’ve now 4 instances of the job-board service running and Railway will automatically distribute the incoming requests to these instances.

Adding replicas to the Job Board service in Railway
Adding replicas to the Job Board service in Railway

Conclusion

After completing this tutorial, you will have learned about scaling up a SaaS application on the Railway. You also learned about utilizing object storage and HTTP caching for better performance. It is important to understand that when getting starting speed is important to validate the ideas quickly and using services such as Railway helps you as a solopreneur to ship your ideas as fast as possible.