Skip to content

Fastify

The Fastify adapter integrates Uploadista with Fastify applications, offering the highest performance for Node.js file upload servers. Features built-in WebSocket support and excellent TypeScript integration.

npm install @uploadista/server @uploadista/adapters-fastify fastify

First, define your flows:

flows.ts
import {
createFlow,
createInputNode,
createOutputNode,
createOptimizeNode,
} from "@uploadista/flow";
export const optimizeFlow = createFlow({
flowId: "optimize-image",
name: "Optimize Image",
nodes: {
input: createInputNode("input"),
optimize: createOptimizeNode("optimize", { format: "webp", quality: 80 }),
output: createOutputNode("output"),
},
edges: [
{ source: "input", target: "optimize" },
{ source: "optimize", target: "output" },
],
});
export const flows = {
"optimize-image": optimizeFlow,
};

Then set up the server:

import Fastify from "fastify";
import { createUploadistaServer } from "@uploadista/server";
import { fastifyAdapter } from "@uploadista/adapters-fastify";
import { fileStore } from "@uploadista/data-store-filesystem";
import { fileKvStore } from "@uploadista/kv-store-filesystem";
import { flows } from "./flows";
const fastify = Fastify({ logger: true });
const uploadistaServer = await createUploadistaServer({
dataStore: fileStore({ directory: "./uploads" }),
kvStore: fileKvStore({ directory: "./uploads" }),
flows,
adapter: fastifyAdapter(),
});
// Mount routes
fastify.all("/uploadista/api/*", async (request, reply) => {
return uploadistaServer.handler({ request, reply });
});
await fastify.listen({ port: 3000 });
import { imagePlugin } from "@uploadista/flow-images-sharp";
import { redisEventBroadcaster } from "@uploadista/event-broadcaster-redis";
const uploadistaServer = await createUploadistaServer({
// Required
dataStore: s3Store({ /* config */ }), // File storage backend
kvStore: redisKvStore({ /* config */ }), // Metadata storage
flows, // Flow definitions object
adapter: fastifyAdapter({
authMiddleware: async (ctx) => ({ clientId: "user-123" }), // Optional
}),
// Optional
plugins: [imagePlugin()], // Processing plugins
eventBroadcaster: redisEventBroadcaster({ /* config */ }), // Multi-instance sync
withTracing: true, // OpenTelemetry tracing
baseUrl: "uploadista", // API base path (default)
});
import Fastify from "fastify";
import websocket from "@fastify/websocket";
import cors from "@fastify/cors";
import rateLimit from "@fastify/rate-limit";
import { createClient } from "redis";
import { createUploadistaServer } from "@uploadista/server";
import { fastifyAdapter } from "@uploadista/adapters-fastify";
import { s3Store } from "@uploadista/data-store-s3";
import { redisKvStore } from "@uploadista/kv-store-redis";
import { imagePlugin } from "@uploadista/flow-images-sharp";
import { flows } from "./flows";
// Initialize Redis
const redisClient = createClient({
url: process.env.REDIS_URL || "redis://localhost:6379",
});
await redisClient.connect();
const fastify = Fastify({ logger: true, bodyLimit: 50 * 1024 * 1024 });
await fastify.register(websocket);
await fastify.register(cors, { origin: '*' });
await fastify.register(rateLimit, { max: 100, timeWindow: '15 minutes' });
const uploadistaServer = await createUploadistaServer({
dataStore: s3Store({
deliveryUrl: process.env.CDN_URL!,
s3ClientConfig: {
bucket: process.env.S3_BUCKET!,
region: process.env.AWS_REGION!,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
},
},
}),
kvStore: redisKvStore({ redis: redisClient }),
flows,
plugins: [imagePlugin()],
adapter: fastifyAdapter({
authMiddleware: async (ctx) => {
const token = ctx.request.headers.authorization?.split(" ")[1];
if (!token) return null;
try {
const payload = await verifyJWT(token, process.env.JWT_SECRET!);
return { clientId: payload.sub, permissions: payload.permissions || [] };
} catch {
return null;
}
},
}),
});
// Binary upload support
fastify.addContentTypeParser(
"application/octet-stream",
{ parseAs: "buffer" },
(req, body, done) => done(null, body)
);
// HTTP routes
fastify.all("/uploadista/api/*", async (request, reply) => {
return uploadistaServer.handler({ request, reply });
});
// WebSocket routes for real-time progress
fastify.get(
"/uploadista/ws/upload/:uploadId",
{ websocket: true },
(socket, req) => uploadistaServer.websocketHandler(socket, req.raw)
);
fastify.get(
"/uploadista/ws/flow/:jobId",
{ websocket: true },
(socket, req) => uploadistaServer.websocketHandler(socket, req.raw)
);
await fastify.listen({ port: 3000, host: '0.0.0.0' });
// Graceful shutdown
process.on("SIGTERM", async () => {
await uploadistaServer.dispose();
await redisClient.quit();
await fastify.close();
process.exit(0);
});
  • Built-in validation schemas
  • Automatic request/response serialization
  • Plugin ecosystem
  • Fastest Node.js framework
  • Built-in health endpoints

The server automatically creates these routes:

POST /uploadista/api/upload Create upload
GET /uploadista/api/upload/:uploadId Get upload status
PATCH /uploadista/api/upload/:uploadId Upload chunk
DELETE /uploadista/api/upload/:uploadId Delete upload
POST /uploadista/api/flow/:flowId/:storageId Execute flow
GET /uploadista/api/jobs/:jobId/status Get job status
PATCH /uploadista/api/jobs/:jobId/resume/:nodeId Resume paused flow
GET /uploadista/api/health Health check
GET /uploadista/api/ready Readiness check