Railway & Node.jsApp RouterSEO & Social Cards

Deploying a Node.js Image Generation Service on Railway

A technical tutorial explaining how to configure and host an image manipulation microservice without performance issues.

OG
OGCraft Team
Developer Relations
August 20, 2026
3 min read
Next.js App Router Guide
1200 × 630 px
OpenGraph Preview Card

Deploying a Node.js Image Generation Service on Railway

OGCraft API • Auto Generated
ogcraft.dev

Generating dynamic images (like OpenGraph banners, personalized invoices, or custom certificates) on the fly is a classic requirement for modern web apps. However, if you've ever tried to deploy an image manipulation library like Puppeteer or Canvas to a standard serverless function or container on Railway, you've likely encountered strict memory limits, missing shared OS libraries, and dreaded timeout errors.

In this post, we will look at the harsh reality of hosting your own Chromium instances, and why offloading this workload to a specialized API like OGCraft is the smartest architectural decision for your Node.js or Express backend.


1

The Pain of DIY: Puppeteer on Railway

A standard Express.js server acts as the entry point. However, simply launching a new Chromium instance for every incoming HTTP request will quickly consume all available RAM and crash your Railway container.

src/bad-server.ts
typescript
import express from 'express';
import puppeteer from 'puppeteer';

const app = express();

app.get('/api/generate', async (req, res) => {
  // WARNING: Launching a browser per request will crash your Railway container!
  const browser = await puppeteer.launch({
    args: ['--no-sandbox', '--disable-dev-shm-usage']
  });
  const page = await browser.newPage();
  
  await page.setContent('<h1>Hello World</h1>');
  const buffer = await page.screenshot();
  
  await browser.close();
  
  res.setHeader('Content-Type', 'image/png');
  res.send(buffer);
});

Beyond the code, you also have to manage a massive custom Dockerfile just to install missing OS-level fonts (like CJK fonts to prevent the dreaded "tofu" squares) and X11 libraries required by Chromium. This adds hundreds of megabytes to your Docker image.


2

The OGCraft Solution

Instead of fighting with Docker, Nixpacks, and out-of-memory (OOM) kills, you can use OGCraft. You simply pass your parameters via URL, and OGCraft handles the rendering in milliseconds.

In your Node.js API, you just construct the URL and either redirect the client or return the image URL:

src/server.ts
typescript
import express from 'express';

const app = express();

app.get('/api/social-image', (req, res) => {
  const title = req.query.title || 'Default Title';
  
  // Construct parameters based on the request
  const params = new URLSearchParams({
    template: 'modern-blog',
    title: title.toString(),
    theme: 'dark',
  });

  // Generate the OGCraft URL
  const ogImageUrl = `https://api.ogcraft.dev/api/v1/generate?${params.toString()}`;

  // Option A: 302 Redirect the bot straight to OGCraft (Saves bandwidth!)
  return res.redirect(302, ogImageUrl);
  
  // Option B: Return JSON if calling from a frontend client
  // res.json({ url: ogImageUrl });
});

app.listen(3000);
💡
Architecture Tip:

Notice the res.redirect(302). By instructing social scrapers (like TwitterBot) to follow the redirect to OGCraft's Edge CDN, your Railway service never actually downloads or streams the heavy PNG payload, saving you massive amounts of CPU and egress bandwidth.

Conclusion

Dynamic OpenGraph images are no longer an optional luxury—they are a critical component of modern web SEO and social media marketing. Regardless of your stack, injecting custom social cards into your web pages is essential for standing out.

Ready to take your social share preview images to the next level without maintaining complex canvas code?

Start Generating Dynamic OG Images

Build Stunning OG Cards with OGCraft

Customize templates in real-time in our interactive Playground and fetch high-performance OpenGraph images via a simple API URL.