Render Service Types
Detailed explanation of each service type available on Render. Choose the right service type based on your application's needs.
Web Services (type: web)
Purpose
Web services are HTTP servers that handle incoming requests from the internet. They're publicly accessible via HTTPS URLs.
Use Cases
- REST APIs: JSON APIs for mobile apps or frontend applications
- GraphQL servers: GraphQL endpoints for client queries
- Web applications: Server-rendered websites (Django, Rails, Express)
- Full-stack frameworks: Next.js, Nuxt.js, Remix, SvelteKit
- WebSocket servers: Real-time communication servers
- SSR applications: Server-side rendered React, Vue, or Angular apps
Key Characteristics
- Public URL: Automatically assigned
https://[service-name].onrender.com - Port binding required: Must bind to
0.0.0.0:$PORT - Health checks: Render pings your service to verify it's running
- HTTPS: Automatic SSL/TLS certificates
- Load balancing: Traffic distributed across multiple instances
- Custom domains: Support for your own domain names
Required Configuration
type: web
name: my-api
runtime: node
buildCommand: npm ci
startCommand: npm start
Best Practices
- Bind to environment PORT:
const PORT = process.env.PORT || 3000;
app.listen(PORT, '0.0.0.0');
- Add health check endpoint:
app.get('/health', (req, res) => {
res.status(200).json({ status: 'ok' });
});
-
Use appropriate timeouts: Web requests should complete within 30 seconds
-
Implement graceful shutdown: Handle SIGTERM signals properly
Worker Services (type: worker)
Purpose
Worker services run background tasks without handling HTTP requests. They're not publicly accessible.
Use Cases
- Queue processors: Redis queue, BullMQ, Celery, Sidekiq
- Background jobs: Email sending, image processing, data exports
- Event consumers: Message queue consumers (Kafka, RabbitMQ, etc.)
- Data pipeline workers: ETL processes, data transformation
- Scheduled background tasks: Continuous processes (not cron)
- WebSocket backend: Dedicated WebSocket handler services
Key Characteristics
- No public URL: Not accessible from internet
- No port binding: Doesn't need to listen on a port
- No health checks: Render monitors process health differently
- Long-running: Can run indefinitely
- Private communication: Access via internal networking
- Restart on crash: Automatically restarted if process dies
Required Configuration
type: worker
name: queue-processor
runtime: python
buildCommand: pip install -r requirements.txt
startCommand: celery -A tasks worker --loglevel=info
Best Practices
- Connect to message queue:
import redis
r = redis.from_url(os.environ['REDIS_URL'])
-
Implement retry logic: Handle failures gracefully
-
Monitor queue depth: Track pending jobs
-
Log processing status: Make debugging easier
-
Graceful shutdown: Finish current jobs before exiting
Common Patterns
Node.js with BullMQ:
type: worker
name: job-processor
runtime: node
buildCommand: npm ci
startCommand: node worker.js
envVars:
- key: REDIS_URL
fromDatabase:
name: redis
property: connectionString
Python with Celery:
type: worker
name: celery-worker
runtime: python
buildCommand: pip install -r requirements.txt
startCommand: celery -A app.celery worker
envVars:
- key: REDIS_URL
fromDatabase:
name: redis
property: connectionString
Cron Jobs (type: cron)
Purpose
Cron jobs run scheduled tasks on a repeating schedule. They execute, complete, and shut down.
Use Cases
- Database backups: Regular automated backups
- Report generation: Daily/weekly reports
- Data cleanup: Delete old records periodically
- Cache warming: Pre-populate caches
- Email digests: Send scheduled email summaries
- Data synchronization: Sync between systems
- Batch processing: Process accumulated data
Key Characteristics
- Scheduled execution: Runs on cron schedule
- Automatic shutdown: Shuts down after completing
- No persistent port: Doesn't maintain listening port
- No health checks: Task either completes or fails
- UTC timezone: All schedules in UTC
- Maximum runtime: Jobs timeout after configured limit
Required Configuration
type: cron
name: daily-backup
runtime: node
schedule: "0 2 * * *" # Daily at 2 AM UTC
buildCommand: npm ci
startCommand: node scripts/backup.js
Schedule Format
Standard cron syntax: minute hour day month weekday
Common schedules:
| Schedule | Description |
|---|---|
*/5 * * * * |
Every 5 minutes |
0 * * * * |
Every hour |
0 0 * * * |
Daily at midnight UTC |
0 9 * * 1-5 |
Weekdays at 9 AM UTC |
0 0 1 * * |
First day of each month |
0 9 * * 1 |
Every Monday at 9 AM UTC |
Best Practices
-
Handle failures gracefully: Jobs should be idempotent
-
Log completion status: Track success/failure
-
Set appropriate timeouts: Match expected job duration
-
Use UTC times: All schedules are UTC-based
-
Test thoroughly: Test with different data scenarios
Example Use Cases
Daily Database Backup:
type: cron
name: db-backup
runtime: python
schedule: "0 1 * * *" # 1 AM UTC daily
buildCommand: pip install -r requirements.txt
startCommand: python scripts/backup.py
envVars:
- key: DATABASE_URL
fromDatabase:
name: postgres
property: connectionString
- key: S3_BUCKET
value: my-backups
Hourly Cache Refresh:
type: cron
name: cache-refresh
runtime: node
schedule: "0 * * * *" # Top of every hour
buildCommand: npm ci
startCommand: node scripts/refresh-cache.js
Static Sites (type: web + runtime: static)
Purpose
Serve static HTML, CSS, and JavaScript files via CDN. No backend runtime.
Use Cases
- Single Page Applications (SPAs): React, Vue, Angular apps
- Static site generators: Gatsby, Next.js (static export), Hugo
- Documentation sites: MkDocs, Docusaurus, VitePress
- Landing pages: Marketing sites
- Portfolio sites: Personal websites
- JAMstack sites: Static sites with API integration
Key Characteristics
- CDN delivery: Global edge caching
- No backend runtime: Only serves built files
- Build output only: Serves contents of build directory
- Routing support: Rewrite rules for SPA routing
- Custom headers: Cache control, security headers
- Fast deployment: Quick to build and deploy
Required Configuration
type: web
name: frontend
runtime: static
buildCommand: npm ci && npm run build
staticPublishPath: ./dist # or ./build, ./out, ./public
Routing for SPAs
Single Page Applications need rewrite rules to handle client-side routing:
type: web
name: react-app
runtime: static
buildCommand: npm ci && npm run build
staticPublishPath: ./build
routes:
- type: rewrite
source: /*
destination: /index.html
Custom Headers
Add cache control and security headers:
type: web
name: static-site
runtime: static
buildCommand: npm ci && npm run build
staticPublishPath: ./dist
headers:
# Cache static assets
- path: /static/*
name: Cache-Control
value: public, max-age=31536000, immutable
# Security headers
- path: /*
name: X-Frame-Options
value: DENY
- path: /*
name: X-Content-Type-Options
value: nosniff
Build Filters
For monorepos, only build when frontend files change:
type: web
name: frontend
runtime: static
buildCommand: npm ci && npm run build
staticPublishPath: ./dist
buildFilter:
paths:
- frontend/**
ignoredPaths:
- frontend/**/*.test.js
- frontend/README.md
Best Practices
-
Optimize build output: Minify, compress, tree-shake
-
Use proper cache headers: Long cache for hashed assets
-
Add security headers: Protect against common attacks
-
Configure SPA routing: Add rewrite rules for client routing
-
Handle 404s: Create custom 404.html page
Private Services (type: pserv)
Purpose
Internal services accessible only within your Render account. Not exposed to the internet.
Use Cases
- Internal APIs: Services accessed only by other services
- Database proxies: Connection pools, read replicas
- Microservices: Service mesh architectures
- Admin tools: Internal dashboards
- Cache layers: Internal caching services
- Message brokers: Internal message queues
Key Characteristics
- No public URL: Only accessible via internal DNS
- Internal networking: Fast, low-latency connections
- Port binding required: Must bind to
0.0.0.0:$PORT - Private DNS:
[service-name].render-internal.com - Same-account only: Only accessible from same account
- No internet access: Traffic stays within Render network
Required Configuration
type: pserv
name: internal-api
runtime: node
buildCommand: npm ci
startCommand: npm start
Accessing Private Services
From other services in the same account:
// Use .render-internal.com domain
const API_URL = 'http://internal-api.render-internal.com:10000';
Or use service references:
services:
- type: web
name: frontend
runtime: node
envVars:
- key: INTERNAL_API_URL
fromService:
name: internal-api
type: pserv
property: hostport
Best Practices
-
Use internal DNS: Always use
.render-internal.comdomains -
No authentication needed: Already isolated to account
-
Fast communication: Low latency between services
-
Simplify architecture: No need for external load balancers
Comparison Table
| Feature | Web | Worker | Cron | Static | Private |
|---|---|---|---|---|---|
| Public URL | ✅ Yes | ❌ No | ❌ No | ✅ Yes | ❌ No |
| Port Binding | ✅ Required | ❌ Not needed | ❌ Not needed | ❌ N/A | ✅ Required |
| Health Checks | ✅ Yes | ❌ No | ❌ No | ❌ N/A | ✅ Yes |
| Runtime | ✅ Yes | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes |
| Persistent | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | ✅ Yes |
| Scaling | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | ✅ Yes |
| Use Case | HTTP servers | Background jobs | Scheduled tasks | Static files | Internal services |
Choosing the Right Service Type
Use Web Service when:
- Your app handles HTTP requests
- Users need to access it via URL
- You need load balancing and scaling
Use Worker Service when:
- Processing background jobs
- Consuming from message queues
- Running long-lived processes without HTTP
Use Cron Job when:
- Running scheduled tasks
- Processing doesn't need to be always-on
- Tasks run periodically (hourly, daily, weekly)
Use Static Site when:
- Serving pre-built HTML/CSS/JS
- No backend processing needed
- Want CDN caching and fast delivery
Use Private Service when:
- Service only accessed by other services
- Want internal-only communication
- Building microservice architectures