Hey hey, I'm new here so first of all welcome ever...
# ask-questions
n
Hey hey, I'm new here so first of all welcome everyone! I'm just starting my Growthbook adventure and I've already stumbled upon a couple of things I'd like to clarify. I have an Inngest application running on Next.js API routes (with app router) and I'd like to leverage feature flags and experiments within that app. I've set up Growthbook integration based on the quick start guid popping up in the dashboard when you select new
SDK Connection
and my code currently looks like that:
Copy code
import { growthbookAdapter } from "@flags-sdk/growthbook";
import type { Identify } from "flags";
import { flag } from "flags/next";

growthbookAdapter.setTrackingCallback(async (experiment, result) => {
  console.log("Viewed Experiment", {
    experimentId: experiment.key,
    variationId: result.key,
  });
});

type UserAttributes = {
  id: string;
};

export const identify = (() => {
  return { id: "abc" };
}) satisfies Identify<UserAttributes>;

export const testFlag = flag<boolean>({
  key: "test_feature",
  adapter: growthbookAdapter.feature<boolean>(),
  identify,
});

export const stringTestFeature = flag<string>({
  key: "string_test_feature",
  adapter: growthbookAdapter.feature<string>(),
  identify,
});
My issue is that whenever I change the value for any of my flags, the SDK returns old value until I restart my local server. Is it only because locally it's a long running server and the issue is not gonna be present when deployed to Vercel, or do I have to perform some additional steps in order to enforce refetching the data from Growthbook? Thanks upfront!
f
we support server send events to keep flag states and rules updated almost real time
if you're using client side rendering
n
This is purely backend app, no pages rendered
f
I see
I can check with the team, I don't know the correct way to update off the top of my head
n
Cool, thank you. Isn't that a super common scenario though? You change a flag value and you'd like it to be reflected immediately in your app, right? Or am I missing something? Sorry, I'm pretty new to this kind of solutions. What is the default behaviour of the Next.js SDK, ie. for how long flags will be cached if I don't use server sent events? Perhaps I should use the Javascript SDK instead?
The only way I was able to always fetch the fresh data for now is to recreate the adapter every time I'm evaluating a feature:
Copy code
import { createGrowthbookAdapter } from "@flags-sdk/growthbook";
import { flag } from "flags/next";

import { env } from "~/env.mjs";

const createAdapter = () =>
  createGrowthbookAdapter({
    clientKey: env.GROWTHBOOK_CLIENT_KEY,
    initOptions: {
      skipCache: true,
    },
    clientOptions: {
      disableCache: true,
      trackingCallback: (experiment, result) => {
        console.log("Viewed Experiment", {
          experimentId: experiment.key,
          variationId: result.key,
        });
      },
    },
  });

type UserAttributes = {
  id: string;
};

type GetFlagValueArgs = {
  key: "string_test_feature" | "test_feature";
  attributes: UserAttributes;
};

export function getFlagValue<T>({ key, attributes }: GetFlagValueArgs) {
  const adapter = createAdapter();

  const value = flag<T>({
    key,
    adapter: adapter.feature<T>(),
    identify: () => attributes,
  });

  return value();
}
Okay, I think I've had my 💡 moment now. I managed to figure out I can call
adapter.growthbook.refreshFeatures()
instead of recreating the adapter each time. So now my code looks like this:
Copy code
import { createGrowthbookAdapter } from "@flags-sdk/growthbook";
import { flag } from "flags/next";

import { env } from "~/env.mjs";

const adapter = createGrowthbookAdapter({
  clientKey: env.GROWTHBOOK_CLIENT_KEY,
  clientOptions: {
    trackingCallback: (experiment, result) => {
      console.log("Viewed Experiment", {
        experimentId: experiment.key,
        variationId: result.key,
      });
    },
  },
});

type UserAttributes = {
  id: string;
};

type GetFlagValueArgs = {
  key: "string_test_feature" | "test_feature";
  attributes: UserAttributes;
};

export async function getFlagValue<T>({ key, attributes }: GetFlagValueArgs) {
  await adapter.growthbook.refreshFeatures({ skipCache: true });

  const value = flag<T>({
    key,
    adapter: adapter.feature<T>(),
    identify: () => attributes,
  });

  return value();
}
And now, knowing that I can just call
adapter.growthbook.refreshFeatures()
, I can do one of the following for the long term solutions: • run this periodically as a cron job (e.g. every 5 minutes) • leverage Growthbook's webhooks to call it on demand when feature flags change in the dashboard Am I on the right track?