Skip to main content

Lambdas / Serverless

Vercel / Next.js Serverless

Vercel serverless functions freeze the process after the response is sent, which means background telemetry timers won't fire. Use flush() with Next.js after() to ensure telemetry is sent before the function freezes.

import { Quonfig } from "@quonfig/node";
import { after } from "next/server";

// Singleton — initialized once per cold start
let quonfig: Quonfig | null = null;

async function getQuonfig(): Promise<Quonfig> {
if (!quonfig) {
const client = new Quonfig({
sdkKey: process.env.QUONFIG_SDK_KEY!,
enableSSE: true,
enablePolling: true,
});
await client.init();
quonfig = client;
}
return quonfig;
}

// In a Next.js Server Component or Route Handler:
export default async function MyPage() {
const quonfig = await getQuonfig();
const showBanner = quonfig.isEnabled("show-banner");

// flush telemetry after the response is sent, before Vercel freezes the function
after(() => quonfig.flush());

return <div>{showBanner && <Banner />}</div>;
}

after() runs your callback after the response is sent to the client but before Vercel freezes the Lambda. This ensures evaluation summaries, context shapes, and example contexts are delivered on every request.


Netlify / AWS Lambda

TypeScript Support

⭐ Recommended: Use the Quonfig CLI to generate TypeScript definitions for type-safe access to your flags and configs:

npx @quonfig/cli generate --targets node-ts

Choosing an Approach

The first step is to choose between a client-side style or server-side style approach. We've written a blog post that goes into detail about choosing how to use Quonfig with Netlify.

Feature Flags in Lambdas: The Browser-Like Approach

A practical solution is to treat Netlify functions similar to a browser. Quonfig's Javascript client, for instance, caches flag evaluations per user in a CDN. Here's a sample code snippet for this approach:

import { quonfig, Context } from "@quonfig/javascript";

export default async (req: Request, context: any) => {
const clientOptions = {
sdkKey: process.env.QUONFIG_FRONTEND_SDK_KEY!, // client SDK key
context: new Context({ user: { key: "1234" } }), // user context
};

await quonfig.init(clientOptions); // initialize with context
if (quonfig.isEnabled("my-flag")) { // check feature flag
// Your code here
}
return new Response("ok");
};

In our testing from a Netlify function we see results around a 50ms latency initially and around then 10ms for each subsequent request for the same context. That may be too slow for some applications, but it's a good starting point and very easy to set up.

The nice thing about this solution is that you're going to get instant updates when you change a flag. The next request will have up to date data.

The Server-Side Alternative

Alternatively, you can implement a server-side strategy using the Quonfig NodeJS client. The key will be configuring our client to disable background updates and background telemetry, then performing an update on our own timeline.

Here's a sample code snippet for this approach:

First, generate your types:

npx @quonfig/cli generate --targets node-ts

Then set up your Lambda with full type safety:

import { Quonfig, type Contexts } from "@quonfig/node";
import { QuonfigTypesafeNode } from "./generated/quonfig-server";

const baseQuonfig = new Quonfig({
sdkKey: process.env.QUONFIG_BACKEND_SDK_KEY!,
enableSSE: false, // we don't want any background process in our function
enablePolling: false, // we'll handle updates ourselves
contextUploadMode: "none", // turn off background telemetry
collectEvaluationSummaries: false, // turn off background telemetry
});

// initialize once on cold start
await baseQuonfig.init();

// Create typed instance
const quonfig = new QuonfigTypesafeNode(baseQuonfig);

export default async (req: Request, context: any) => {
const { userId } = context.params;
const quonfigContext: Contexts = { user: { key: userId } };

// Use type-safe methods with context
if (quonfig.myFlag(quonfigContext)) {
// Your code here with full type safety
}

const userConfig = quonfig.userSpecificConfig(quonfigContext);

// every 60 seconds, check for updates in-process
baseQuonfig.updateIfStalerThan(60 * 1000);
return new Response("ok");
};

export const config = { path: "/users/:userId" };

With this approach, most of our requests will be fast, but we'll have a periodic update that will take a bit longer. This is about 50ms in my testing from a Netlify function. We're entirely in control of the frequency here, so it's a judgment call on how real-time you want your feature flag updates. You could even disable the updates altogether if tail latency is of utmost concern and you didn't mind redeploying to update your flags.