npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@siddharatha/adapter-node-rolldown

v1.0.8

Published

High-performance SvelteKit adapter for Node.js with Polka, WebSockets, and OpenTelemetry

Readme

@sveltejs/adapter-node-rolldown

High-performance SvelteKit adapter for Node.js with Polka, WebSocket support, OpenTelemetry tracing, and optimizations for ECS/Kubernetes deployments.

Features

  • 🚀 Ultra-fast: Uses Polka (~30x faster than Express)
  • Bundled: Uses Rollup to bundle server code (only production deps needed)
  • 🔧 Instrumentation: Full support for SvelteKit's instrumentation API
  • �🗜️ Smart compression: Gzip/Brotli with pre-compression support
  • 🔌 WebSocket support: Built-in WebSocket server with ws
  • 📊 OpenTelemetry: Full distributed tracing with Dynatrace integration
  • 🏥 Health checks: /health and /readiness endpoints for K8s
  • 🔄 Graceful shutdown: Proper SIGTERM handling for zero-downtime deployments
  • 📦 High body limits: Configurable request size limits (default 10MB)
  • 🎯 Container-ready: Optimized for Docker, ECS, and Kubernetes

Installation

npm install @sveltejs/adapter-node-rolldown

Usage

In your svelte.config.js:

import adapter from '@sveltejs/adapter-node-rolldown';

export default {
  kit: {
    adapter: adapter({
      // All options are optional with sensible defaults
      out: 'build',
      precompress: true,
      compression: true,
      compressionLevel: 6,
      bodyLimit: '10mb',
      websocket: true,
      websocketPath: '/ws',
      telemetry: true,
      telemetrySampleRate: 1.0,
      healthCheck: true,
      gracefulShutdownTimeout: 30000,
      
      // 🆕 Rolldown bundling options
      external: ['polka', 'sirv', 'compression', 'ws'],  // Keep these external
      // OR use a function:
      // external: (pkg) => Object.keys(pkg.dependencies || {}),
      bundleAll: false,  // true = bundle everything (no node_modules at runtime)
      rolldownOptions: {}  // Additional rolldown config
    })
  }
};

Configuration Options

Basic Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | out | string | 'build' | Output directory for the build | | precompress | boolean | true | Pre-compress static assets with gzip and brotli | | envPrefix | string | '' | Prefix for environment variables |

Performance Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | compression | boolean | true | Enable runtime compression middleware | | compressionLevel | number | 6 | Compression level (1-9) | | bodyLimit | string\|number | '10mb' | Maximum request body size |

WebSocket Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | websocket | boolean | true | Enable WebSocket support | | websocketPath | string | '/ws' | WebSocket endpoint path |

OpenTelemetry Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | telemetry | boolean | true | Enable OpenTelemetry tracing | | telemetrySampleRate | number | 1.0 | Sampling rate (0.0-1.0) | | telemetryConfig | object | {} | Additional telemetry configuration |

Container Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | healthCheck | boolean | true | Enable health check endpoints | | gracefulShutdownTimeout | number | 30000 | Graceful shutdown timeout (ms) | | polyfill | boolean | true | Inject global polyfills |

Bundling Options 🆕

| Option | Type | Default | Description | |--------|------|---------|-------------| | external | string[] or function | undefined | Packages to exclude from bundle (see examples below) | | bundleAll | boolean | false | Bundle everything including dependencies | | rolldownOptions | object | {} | Additional Rolldown configuration |

External Package Examples

Array of packages:

adapter({
  external: ['polka', 'sirv', 'compression', 'ws']
})

Function with custom logic:

adapter({
  external: (pkg) => {
    // Keep runtime packages external
    const runtime = ['polka', 'sirv', 'compression', 'ws'];
    // Bundle OpenTelemetry to avoid version conflicts
    return runtime;
  }
})

Bundle everything (no externals):

adapter({
  bundleAll: true  // Zero node_modules at runtime
})

Default (uses package.json dependencies):

adapter({
  // No external option = uses package.json dependencies
})

Environment Variables

Server Configuration

# Server binding
PORT=3000
HOST=0.0.0.0

# Performance tuning
KEEP_ALIVE_TIMEOUT=65000
HEADERS_TIMEOUT=66000
MAX_REQUESTS_PER_SOCKET=0

# Trust proxy headers (if behind load balancer)
TRUST_PROXY=true

OpenTelemetry Configuration

# Enable/disable telemetry at runtime
OTEL_ENABLED=true

# Service identification
OTEL_SERVICE_NAME=my-sveltekit-app
OTEL_SERVICE_VERSION=1.0.0

# Exporter configuration
OTEL_EXPORTER_OTLP_ENDPOINT=https://your-env.live.dynatrace.com/api/v2/otlp/v1/traces
OTEL_EXPORTER_OTLP_PROTOCOL=http  # or 'grpc'

# Dynatrace API token (for authentication)
DYNATRACE_API_TOKEN=your-api-token-here

# Sampling rate (override adapter config)
OTEL_SAMPLE_RATE=1.0

WebSocket Configuration

# Enable/disable at runtime
WEBSOCKET_ENABLED=true
WEBSOCKET_PATH=/ws

Deployment

Building

npm run build
cd build
npm install --omit=dev
node index.js

Docker

Example Dockerfile:

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app

# Install only production dependencies
COPY --from=builder /app/build/package.json ./
RUN npm install --omit=dev

# Copy built application
COPY --from=builder /app/build ./

# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001 && \
    chown -R nodejs:nodejs /app

USER nodejs

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s \
  CMD node -e "require('http').get('http://localhost:3000/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"

EXPOSE 3000

CMD ["node", "index.js"]

Build and run:

docker build -t my-sveltekit-app .
docker run -p 3000:3000 \
  -e OTEL_ENABLED=true \
  -e OTEL_EXPORTER_OTLP_ENDPOINT=https://your-env.live.dynatrace.com/api/v2/otlp/v1/traces \
  -e DYNATRACE_API_TOKEN=your-token \
  my-sveltekit-app

Kubernetes

Example deployment manifest:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sveltekit-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sveltekit-app
  template:
    metadata:
      labels:
        app: sveltekit-app
    spec:
      containers:
      - name: app
        image: my-sveltekit-app:latest
        ports:
        - containerPort: 3000
          name: http
          protocol: TCP
        env:
        - name: PORT
          value: "3000"
        - name: HOST
          value: "0.0.0.0"
        - name: OTEL_ENABLED
          value: "true"
        - name: OTEL_SERVICE_NAME
          value: "sveltekit-app"
        - name: OTEL_EXPORTER_OTLP_ENDPOINT
          valueFrom:
            secretKeyRef:
              name: dynatrace-config
              key: endpoint
        - name: DYNATRACE_API_TOKEN
          valueFrom:
            secretKeyRef:
              name: dynatrace-config
              key: api-token
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 3
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /readiness
            port: 3000
          initialDelaySeconds: 10
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 2
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        lifecycle:
          preStop:
            exec:
              command: ["/bin/sh", "-c", "sleep 10"]
---
apiVersion: v1
kind: Service
metadata:
  name: sveltekit-app
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 3000
    protocol: TCP
    name: http
  selector:
    app: sveltekit-app

ECS Task Definition

{
  "family": "sveltekit-app",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "containerDefinitions": [
    {
      "name": "app",
      "image": "my-sveltekit-app:latest",
      "portMappings": [
        {
          "containerPort": 3000,
          "protocol": "tcp"
        }
      ],
      "environment": [
        { "name": "PORT", "value": "3000" },
        { "name": "HOST", "value": "0.0.0.0" },
        { "name": "OTEL_ENABLED", "value": "true" },
        { "name": "OTEL_SERVICE_NAME", "value": "sveltekit-app" }
      ],
      "secrets": [
        {
          "name": "DYNATRACE_API_TOKEN",
          "valueFrom": "arn:aws:secretsmanager:region:account:secret:dynatrace-token"
        },
        {
          "name": "OTEL_EXPORTER_OTLP_ENDPOINT",
          "valueFrom": "arn:aws:secretsmanager:region:account:secret:dynatrace-endpoint"
        }
      ],
      "healthCheck": {
        "command": ["CMD-SHELL", "wget -q --spider http://localhost:3000/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 40
      },
      "stopTimeout": 35,
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/sveltekit-app",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "ecs"
        }
      }
    }
  ]
}

WebSocket Usage

The adapter includes a WebSocket server on /ws by default. You can customize the WebSocket behavior by modifying files/index.js:

wsServer.on('connection', (ws, req) => {
  console.log('WebSocket connection established');
  
  ws.on('message', (data) => {
    const message = JSON.parse(data.toString());
    
    // Your custom WebSocket logic here
    ws.send(JSON.stringify({ 
      type: 'response', 
      data: 'processed' 
    }));
  });
});

Client-side usage:

const ws = new WebSocket('ws://localhost:3000/ws');

ws.onopen = () => {
  ws.send(JSON.stringify({ type: 'hello' }));
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Received:', data);
};

Server Instrumentation

The adapter fully supports SvelteKit's instrumentation API. Create a src/instrumentation.server.js file in your SvelteKit project:

// src/instrumentation.server.js
export async function initialize() {
  console.log('Server instrumentation initialized!');
  
  // Initialize monitoring, databases, caches, etc.
  await connectToDatabase();
  await initializeCache();
  
  // This runs before the server starts accepting requests
}

The instrumentation file will be automatically bundled and executed before your server starts.

Instrumentation with OpenTelemetry

You can combine instrumentation with OpenTelemetry for enhanced monitoring:

// src/instrumentation.server.js
import { trace } from '@opentelemetry/api';

export async function initialize() {
  const tracer = trace.getTracer('app-initialization');
  const span = tracer.startSpan('server-init');
  
  try {
    await setupApplication();
    span.addEvent('Application setup complete');
  } catch (error) {
    span.recordException(error);
    throw error;
  } finally {
    span.end();
  }
}

OpenTelemetry & Dynatrace

The adapter automatically instruments:

  • HTTP requests (incoming and outgoing)
  • Database queries (PostgreSQL, MySQL, MongoDB, Redis)
  • External API calls
  • Custom spans (if needed)

Dynatrace Setup

  1. Get your Dynatrace environment ID and API token
  2. Set environment variables:
OTEL_ENABLED=true
OTEL_EXPORTER_OTLP_ENDPOINT=https://{your-env-id}.live.dynatrace.com/api/v2/otlp/v1/traces
DYNATRACE_API_TOKEN=your-api-token
OTEL_SERVICE_NAME=my-sveltekit-app
  1. Traces will appear in Dynatrace's Distributed Traces view

Custom Spans

import { trace } from '@opentelemetry/api';

const tracer = trace.getTracer('my-app');

export async function load() {
  const span = tracer.startSpan('custom-operation');
  
  try {
    // Your code here
    span.addEvent('Processing started');
    const result = await processData();
    span.setAttribute('result.count', result.length);
    return { data: result };
  } finally {
    span.end();
  }
}

Performance Benchmarks

Compared to @sveltejs/adapter-node:

  • ~30x faster routing (Polka vs Express)
  • ~40% smaller bundle size
  • ~25% faster cold starts
  • Pre-compression: Serve .gz and .br files directly (zero CPU cost)
  • High throughput: Handle 10MB+ request bodies without issues

Monitoring & Observability

Health Check Endpoints

  • GET /health - Liveness probe (returns 200 if server is alive)
  • GET /readiness - Readiness probe (returns 200 if ready to accept traffic)

Metrics (via OpenTelemetry)

The adapter automatically collects:

  • Request duration and count
  • HTTP status codes
  • Database query performance
  • Memory and CPU usage
  • WebSocket connections

Graceful Shutdown

The server handles SIGTERM and SIGINT signals:

  1. Stop accepting new connections
  2. Close existing WebSocket connections
  3. Flush OpenTelemetry traces
  4. Exit after timeout (default 30s)

Troubleshooting

High Memory Usage

Reduce OpenTelemetry sampling rate:

adapter({
  telemetrySampleRate: 0.1  // Sample only 10% of requests
})

WebSocket Connection Issues

Ensure your load balancer supports WebSocket upgrades:

  • ALB: Enable sticky sessions
  • NGINX: Add proxy_http_version 1.1; and proxy_set_header Upgrade $http_upgrade;

Compression Not Working

Check content types and sizes:

  • Minimum size: 1KB (threshold)
  • Images/videos are not compressed
  • Pre-compressed files (.gz, .br) are served if available

License

MIT

Contributing

Contributions welcome! Please open an issue or PR on GitHub.