← Files RenderARCHIVED FILE
skills/render-deploy/references/service-types.md
11.8 KB · Oct 4, 2026 · 06:02 UTC
# 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
```yaml
type: web
name: my-api
runtime: node
buildCommand: npm ci
startCommand: npm start
```
### Best Practices
1. **Bind to environment PORT**:
```javascript
const PORT = process.env.PORT || 3000;
app.listen(PORT, '0.0.0.0');
```
2. **Add health check endpoint**:
```javascript
app.get('/health', (req, res) => {
res.status(200).json({ status: 'ok' });
});
```
3. **Use appropriate timeouts**: Web requests should complete within 30 seconds
4. **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
```yaml
type: worker
name: queue-processor
runtime: python
buildCommand: pip install -r requirements.txt
startCommand: celery -A tasks worker --loglevel=info
```
### Best Practices
1. **Connect to message queue**:
```python
import redis
r = redis.from_url(os.environ['REDIS_URL'])
```
2. **Implement retry logic**: Handle failures gracefully
3. **Monitor queue depth**: Track pending jobs
4. **Log processing status**: Make debugging easier
5. **Graceful shutdown**: Finish current jobs before exiting
### Common Patterns
**Node.js with BullMQ:**
```yaml
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:**
```yaml
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
```yaml
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
1. **Handle failures gracefully**: Jobs should be idempotent
2. **Log completion status**: Track success/failure
3. **Set appropriate timeouts**: Match expected job duration
4. **Use UTC times**: All schedules are UTC-based
5. **Test thoroughly**: Test with different data scenarios
### Example Use Cases
**Daily Database Backup:**
```yaml
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:**
```yaml
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
```yaml
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:
```yaml
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:
```yaml
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:
```yaml
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
1. **Optimize build output**: Minify, compress, tree-shake
2. **Use proper cache headers**: Long cache for hashed assets
3. **Add security headers**: Protect against common attacks
4. **Configure SPA routing**: Add rewrite rules for client routing
5. **Handle 404s**: Create custom 404.html page
---
## Private Services (`type: pserv`)
### Purpose
Services that receive traffic only from other Render services on the same private network. They aren't exposed to the public 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 hostname**: Each service has a unique internal hostname
- **Private-network scope**: The connecting service must be in the same workspace and region
- **No public ingress**: Can't be accessed from the public internet
### Required Configuration
```yaml
type: pserv
name: internal-api
runtime: node
buildCommand: npm ci
startCommand: npm start
```
### Internal Addresses
Render gives each web service and private service a unique hostname on the private network. The hostname is stable and maps to instance IPs which can change between deploys. Free web services can't receive private traffic it.
Services can communicate over the private network when they belong to the same workspace and region. Find the internal address in the service's **Connect** menu under **Internal**. Private services also show it as the **Service Address**.
An internal address has the form `internal-hostname:port`. Add the protocol when the client requires one, for example `http://internal-hostname:port`.
In a Blueprint, use `fromService` to inject the address into another service:
```yaml
services:
- type: web
name: frontend
runtime: node
envVars:
- key: API_URL
fromService:
name: internal-api
type: pserv
property: hostport
```
For web services and private services, `host` provides the internal hostname and `hostport` provides the hostname and listening port as `host:port`.
### Best Practices
1. **Use internal addresses**: Use the hostname from the Dashboard or inject it with a Blueprint service reference.
2. **Fast communication**: Low latency between services
3. **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
SHA-256: 2e95dab603df7f692d1e403431985dba88303d490507623165369c0c7b4c2b22