Rivet Containers
Rivet Containers allows you to deploy any application packaged as a Docker container to the cloud. Deploy web servers, game backends, or any custom service with complete control over your runtime environment.
What are containers good for?
- High-Memory Workloads: Applications requiring substantial RAM for processing large data. For example, PDF Processing with document parsing and transformation.
- CPU-Heavy Workloads: Tasks demanding significant computational resources. For example, Media Transcoding with FFmpeg for video conversion.
- Browser Automation: Headless browsers for testing, scraping, or rendering. For example, Web Scraping with Puppeteer or Playwright.
- Sandboxed Code Execution: Safely running untrusted code in isolated environments. For example, MMOs or First-Person Shooters.
- Headless Game Servers: Game backends without rendering requirements. For example, Turn-Based Game Logic for chess or card games.
- Custom Dependencies: Applications requiring specific system libraries or tools. For example, Computer Vision Processing with OpenCV dependencies.
Quickstart
Step 1: Writing a Dockerfile
Create a simple HTTP server in your project:
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end("Hello from Rivet Container!");
});
const port = process.env.PORT_HTTP;
server.listen(port, () => {
console.log(`HTTP server running on port ${port}`);
});
Create a Dockerfile in your project directory:
FROM node:22-alpine
WORKDIR /app
COPY package.json ./
RUN npm install
COPY . .
# Create rivet user and set proper permissions
RUN addgroup -S rivet && \
adduser -S -G rivet rivet && \
chown -R rivet:rivet /app
# Switch to non-root user
USER rivet
CMD ["node", "server.js"]
Ports & environment variables will be passed via the Rivet API
We'll pass the ports & env vars used in the Dockerfile in Step 3. Read more in the API docs for actors.create.
Step 2: Deploying a container
Specify the Dockerfile in your rivet.json
:
{
"containers": {
"my-container": {
"dockerfile": "Dockerfile"
}
}
}
Now deploy your container with:
rivet deploy
Step 3: Starting a container
In this step, you're requesting Rivet to launch your containerized application in the cloud:
import { RivetClient } from "@rivet-gg/api";
// Initialize the Rivet client with your API token
// You can get this from the Rivet dashboard
const client = new RivetClient({
token: process.env.RIVET_TOKEN
});
// Create a container - this launches your container on Rivet's infrastructure
const { actor } = await client.actors.create({
// Your project and environment IDs from the Rivet dashboard
project: "your-project-id",
environment: "your-environment-id",
body: {
// Tags help identify this specific container instance
// You can query containers by these tags later
tags: { name: "my-container" },
// buildTags determine which container code to run
// This should match tags in your rivet.json build configuration
// The current tag is automatically assigned on deploy
buildTags: { name: "my-container", current: "true" },
// Network configuration for your container
network: {
ports: {
http: {
// The protocol used for communication
protocol: "https",
}
}
},
// Optional: Specify a region for lower latency to specific users
// If not specified, Rivet will choose the optimal region
// region: "atl",
// Container resources specification
resources: {
cpu: 1000, // Number of CPU thousanths of a core
memory: 1024, // Memory in MB
}
}
});
// The actor.id is a unique identifier for this container instance
console.log("Created container:", actor.id);
API naming
While this feature is called "Containers" in the UI and documentation, the underlying API uses the term "actors" (e.g., client.actors.create
). This is because there is a lot of overlap between the actor & container APIs.
What happens during creation:
- Rivet finds the latest build matching your
buildTags
- It provisions resources in the specified region (or chooses the best one)
- It starts your container with the provided environment variables
- The container starts running based on your Dockerfile's CMD or ENTRYPOINT
See actors.create for more options.
Step 4: Connecting to a container
Once your container is running, you can access its URL directly from the container object:
// The actor response includes the URL information
// You can access it for any port you configured
const httpUrl = actor.network.ports.http.url;
// The URL is a public endpoint to your container
console.log("Container HTTP URL:", httpUrl);
// Use the URL to communicate with your container
// In this example, we're calling our HTTP server
const response = await fetch(httpUrl);
const text = await response.text();
console.log("Response from container:", text);
What happens during connection:
- Each port configured for your container gets a unique URL
- These URLs are accessible based on your container's security settings
- The URL routes to your container regardless of which region it's in
- For additional security, you can use
getConnection
to generate temporary, authenticated URLs
See actors.get for more details.
Step 5: Destroying a container
When you're finished using the container, it's important to destroy it to free up resources:
// Destroy the container to free up resources and stop billing
await client.actors.destroy(actor.id, {
project: "your-project-id",
environment: "your-environment-id",
});
console.log("Container destroyed");
What happens during destruction:
- Rivet sends a termination signal to your container
- Your container gets a short grace period to clean up resources
- All compute resources associated with the container are freed
- You stop being billed for the container's runtime
See actors.destroy for more details.
Note
Always destroy containers when you're done with them to avoid unnecessary costs. Containers will continue running and billing will continue until explicitly destroyed.
Configuration Options
When configuring your Docker-based build in rivet.json
, you have access to the following options under builds
:
Option | Description | Example |
---|---|---|
dockerfile | Path to the Dockerfile relative to your project | "Dockerfile" , "docker/prod.Dockerfile" |
image | Use an existing image instead of building | "node:22-alpine" |
build_path | Directory containing your build context | "." , "./backend" |
build_target | Target stage in multi-stage builds | "production" , "development" |
build_args | Key-value pairs passed as build arguments | { "NODE_ENV": "production" } |
See the configuration documentation for all available options.
Non-Root User Requirement
For security reasons, Rivet containers cannot run as root. You must explicitly set a non-root user in your Dockerfile.
Different base images require different commands to create non-root users:
RUN addgroup -S rivet && \
adduser -S -G rivet rivet && \
chown -R rivet:rivet /app
USER rivet