Build a ConfigCat alternative

Build a ConfigCat alternative as flags, two environments, and a published JSON file. Pro is $110 a month for a toggle you can host yourself.

  • getting-started
  • vibe-coding
  • scope

You can build a ConfigCat alternative as flags, two environments, and a published JSON file. ConfigCat is that product. The catalog line is “A flag, a JSON file, and an on or off.”

Pro is $110 a month through Smart at $325, billed monthly. Annual billing is $95 a month through $270. The pricing note leaves out Forever Free, Enterprise, and Dedicated. The basic replacement is 10 hours.

Ship this if you still rent a flag service to hide one button. It is marked Weekend. The verdict on the card is “On or off is enough”.

Last time I wrote about vibe coding your own Metabase. That was a teardown. This one is a regular backlog topic. Experiments, a percentage rollout, and an SDK for every language stay on the skip row.

What you need to build a ConfigCat alternative

The ConfigCat page splits the work into three rows.

The first row is the one you want this weekend. Named boolean flags. Two environments, staging and production. A draft you can edit, and a published snapshot the app is allowed to read.

The second row is 3 days. Targeting rules, an audit log, and a second project. “On for Ada” and a history of who published are real, and they can wait until one flag has already shipped.

The third row is a month and up. Experiments, an SDK for every language, and a private cloud. The table labels that row as the part you should skip.

If you tell an agent to “clone ConfigCat”, it aims at the third row. Copy the prompt, then pin it to the first one.

Store Project, Environment, Flag, and ConfigSnapshot. The card also names AuditEntry. The 3-day estimate is where that log sits, next to targeting and a second project. For these 10 hours, a publish overwrites the snapshot and the previous JSON is gone. Add the audit table when you need to answer who flipped it.

A project owns the flags. An environment is staging or production, and it has a key. A flag has a name and a boolean draft per environment. A snapshot is the JSON you published. The draft and the snapshot are different rows. That split is the guardrail on the card. Serve only the published snapshot.

The feature list also names a kill switch. It is the same publish, with that flag forced off in every environment. Leave the button off the 10-hour cut if you want the weekend to stay a JSON file.

Sentry is what you open when the flag hid a bug and the error still fired, at $26–$89 a month. I wrote that teardown. Mixpanel is the funnel, at $140–$2,289 a month. The card points at both and says not to rebuild them here. Metabase is a saved SELECT, which is a different screen from a flag.

How does a ConfigCat alternative work

I am describing the catalog’s model of a flag endpoint. You edit a draft, you publish a snapshot, and the running app reads only that snapshot.

Your browser talks to one Astro app for the editor. Node.js plus Astro is the default. Use TanStack Start if React is your weekday language. The capability line on the card is Astro, Workers, and D1.

The editor writes drafts and snapshots to D1. Publish copies the drafts for one environment into a new snapshot and stores the time. A Worker serves GET for that environment. It loads the snapshot, checks the key, and returns JSON. It does not read the draft table.

The app that you are flagging calls the Worker with the environment key. A missing, unknown, or revoked key gets an empty body, so a leaked staging key cannot list production flags. The guardrail says the read must not leak other flags.

A draft flip of checkout_v2 to on does nothing to the endpoint. The next fetch still returns the last publish. You publish staging, and the following fetch returns on. Production stays on its own snapshot until you publish that environment too.

Here is the body the Worker returns after a publish where the new checkout is off. The names are the flag names you saved.

{
  "checkout_v2": false,
  "banner": true
}

Missing keys in that object are flags you have not published yet. The client treats a missing name as off. Do not invent a second document for defaults.

Every editor query is scoped by owner. A guessed project id from another account returns an empty flag list.

YOUR BROWSER Flag editor and publish Drafts stay on this screen ASTRO APP ON THE REQUEST Save drafts, publish one env Copy values into a snapshot D1 HOLDS THE ROWS Project, flag, snapshot Draft and published stay apart WORKER SERVES THE JSON Published snapshot only Environment key on every read LATER ROWS Targeting rules and an audit log Experiments and a private cloud
Publish copies drafts into a snapshot. The Worker never reads the draft table. Targeting and experiments sit in the dashed box.

The Worker is the read path because the card names a JSON endpoint, and that GET should stay up when you are editing. D1 holds the rows because a flag file for one project is small. Put the environment key in the Worker config the app already has. Do not ship it inside the JSON body.

Screens of a ConfigCat alternative

v1 needs the project, the flag, and the published file.

Projects

Home lists projects. Each row shows the two environments, the flag count, and the last publish time. A new project starts with staging and production, both empty, each with its own key. A second project waits on the 3-day row, so this list can be one row for a while.

WIREFRAME · PROJECTS Shop · 2 flags Staging · published today 09:10 Production · published yesterday OPEN FLAGS A second project waits on the 3-day row
Home is one project and two environments. The publish time is per environment.

Flag editor

The editor lists flags. Each flag has a name, a draft for staging, and a draft for production. The published value sits beside the draft so you can see a flip that is not live yet. Publish is per environment. Publishing staging leaves production alone.

WIREFRAME · FLAGS checkout_v2 Staging draft · on Published · off Production draft · off Published · off PUBLISH STAGING
The draft can be on while the published snapshot is still off. Publish is one environment at a time.

Published config

This screen is the file the app sees. It shows the environment, the key hint (last four characters), the last publish time, and the JSON. The full key is shown once, when the environment is created. A revoked key disappears from this page and the Worker starts rejecting it.

How a ConfigCat alternative publishes a flag

You create Shop with staging and production. You add checkout_v2, default off in both drafts, and you publish staging so the endpoint exists. The JSON says false.

You flip the staging draft to on. You fetch the staging URL with the staging key. The body is still false, because publish has not run. You press publish staging. The next fetch returns true. Production still returns false.

You flip the staging draft back to off and publish again. The endpoint returns false, and the earlier true snapshot is replaced. Two publishes are two snapshots. The 3-day audit row is what would keep both. Until then, the latest snapshot is the one you can read.

A request with the revoked key gets no flag values. A request with the production key does not include the staging snapshot.

ADD CHECKOUT_V2 Default off, both environments FLIP THE STAGING DRAFT Endpoint still returns false PUBLISH STAGING Snapshot copies the drafts APP FETCHES JSON Staging key sees true Production key still sees false
A draft is invisible to the app. Publish is the moment the JSON changes, and only for that environment.

Targeting rules are the 3-day row because “on for this email” needs a user attribute on the read, and the JSON stops being one boolean. Percentage rollouts and experiments are the month row. The non-goal names both, and it points at Mixpanel for funnels. An SDK per language is a client that fetches this same JSON. Write the one client your app needs. Skip the catalog of them.

Start with the first row

Go to Build your own ConfigCat. Copy the Astro prompt, or TanStack Start if that is what you write.

Tell the agent the first estimate only. Flags, environments, a JSON endpoint. Ten hours.

If the rent is an error inbox, use the Sentry teardown. If the rent is a chart of who finished checkout, start from Mixpanel. If the requirement is a percentage experiment across ten languages, keep paying.

Keep reading

Read all articles →