docs

Connect an existing app

link connects the app in the current directory to a Linguana project. It records the project in linguana.json and writes build and browser credentials into an ignored environment file. It does not change your components or Vite configuration.

terminal
cd my-app
npx @linguanahq/cli link

Run it in the app directory, next to package.json. If you are not signed in, the CLI starts browser sign-in first.

  1. Detects the framework from package.json: TanStack Start when @tanstack/react-start is installed, otherwise exactly one of React, Vue, Svelte, or SolidJS. If it finds none or several, pass --framework.
  2. Selects an organization. It uses --organization, the organization of an already linked project, or asks you. You can also create one; the suggested name is <your name>'s workspace. Noninteractive runs select your only organization automatically, and need --new-organization <name> when you have none.
  3. Selects a project. It uses --project, the project already recorded in linguana.json, or asks you to choose an active project or create one. New projects are named after the directory unless you pass --new-project <name>.
  4. Enables languages for a newly created project, or when you pass --locales. Existing projects keep their language settings otherwise.
  5. Writes credentials for the selected environment, reusing a valid existing build token or creating a new one.
  6. Writes linguana.json with "mode": "connected", the organization and project IDs, the API origin, and the source language.
  7. Prints the next steps: your dashboard project link and the integration guide for your framework.

Connecting credentials requires Owner or Admin access to an active organization. Projects pending deletion cannot be linked. Apps created from templates must link to a project with English source content.

Choose resources explicitly

terminal
# Look up IDs
npx @linguanahq/cli orgs list
npx @linguanahq/cli projects list --organization ORGANIZATION_ID

# Link an existing project
npx @linguanahq/cli link --project PROJECT_ID

# Create a project in an existing organization, with three languages
npx @linguanahq/cli link --organization ORGANIZATION_ID --new-project "My app" --locales fr,es,ar

# Create a new organization and project
npx @linguanahq/cli link --new-organization "Acme" --new-project "Storefront"

orgs list and projects list print one ID Name pair per line, or the full API objects with --json. When you omit --organization, projects list asks you to choose one; noninteractive runs select your only organization automatically and otherwise require --organization.

--organization and --new-organization cannot be combined, and neither can --project and --new-project. A new organization cannot hold an existing project. If --project belongs to a different organization than --organization, link stops with PROJECT_SCOPE_MISMATCH.

The environment file

link targets the defaultEnvironment recorded in linguana.json, or development for a new link, and writes .env.local for development. Pass --environment to target another environment:

EnvironmentFile written
development (default).env.local
staging.env.staging.local
production.env.production.local

The file contains matching build and browser values:

.env.local
LINGUANA_PROJECT_ID="PROJECT_ID"
LINGUANA_ENVIRONMENT="development"
LINGUANA_API_URL="https://linguana-api.mohammedibrahim.dev"
LINGUANA_UPLOAD="true"
LINGUANA_TRANSLATE="false"
VITE_LINGUANA_PROJECT_ID="PROJECT_ID"
VITE_LINGUANA_ENVIRONMENT="development"
VITE_LINGUANA_API_URL="https://linguana-api.mohammedibrahim.dev"
VITE_LINGUANA_PUBLISHABLE_KEY="PUBLISHABLE_KEY"
LINGUANA_PROJECT_TOKEN="BUILD_TOKEN"
Build/server variableBrowser variable
LINGUANA_PROJECT_IDVITE_LINGUANA_PROJECT_ID
LINGUANA_ENVIRONMENTVITE_LINGUANA_ENVIRONMENT
LINGUANA_API_URLVITE_LINGUANA_API_URL
LINGUANA_PROJECT_TOKENVITE_LINGUANA_PUBLISHABLE_KEY
LINGUANA_UPLOAD—
LINGUANA_TRANSLATE—

The build token is private. The publishable key is a separate, public catalog-read key. Never prefix build tokens with VITE_. LINGUANA_UPLOAD is true so builds upload their source text; LINGUANA_TRANSLATE is false so builds never start paid translation by themselves.

The CLI also:

  • Adds .env.local, .env.*.local, and .linguana/ to .gitignore when they are missing.
  • Preserves unrelated variables, comments, and line endings, and updates Linguana values in place.
  • Refuses to write an environment file that Git already tracks, or any path that passes through a symbolic link.
  • Writes the file with owner-only permissions.

Conflicting values

If the file already has different values for Linguana variables, the CLI lists the variable names (never their values) and asks before replacing them. Noninteractive runs stop with ENV_CONFLICT instead. Pass --overwrite-env to authorize replacement:

terminal
npx @linguanahq/cli link --project PROJECT_ID --overwrite-env

Duplicate definitions of the same Linguana variable stop with DUPLICATE_ENV; remove the duplicate first.

Wire the values into your app

link configures linkage and credentials only. Your app must read the values:

  • Templates already read them. Restart the dev server after linking.
  • For an existing Vite app, load the environment with Vite's loadEnv in vite.config.ts, add the Linguana adapter before your framework plugin, and pass the public values to the runtime provider. Follow Connect hosted translations, the framework guide, or the TanStack Start guide.

Then run doctor to check the result.

Refresh credentials with env pull

terminal
npx @linguanahq/cli env pull
npx @linguanahq/cli env pull --environment staging
npx @linguanahq/cli env pull --environment production

env pull reads the project from linguana.json, fetches the current public configuration, and validates the local build token. It reuses a valid token for the same project and environment and creates a new one only when needed. Run link first; otherwise env pull stops with PROJECT_NOT_LINKED.

Pulling another environment writes that environment's file and leaves defaultEnvironment in linguana.json unchanged. For Vite apps, build staging with npm run build -- --mode staging; Vite's normal production build reads .env.production.local. Private and public project and environment values must match.

The server cannot return a previously issued token secret again. If the local token is missing, revoked, or scoped to another project or environment, the CLI creates a replacement. When an invalid token is already in the file, it asks before replacing it, or requires --overwrite-env when noninteractive.

Recovery and token reuse

Setup is safe to repeat. Interrupted operations save nonsecret idempotency keys in the ignored .linguana/setup.json, so running link again resumes with the same organization and project instead of creating duplicates.

If a token response was lost, replay returns metadata only; setup revokes that operation's unusable token before creating a replacement. It never rotates unrelated tokens or deletes projects. If writing the environment file fails after a new token was created, the CLI revokes that token.

Only one setup can run in an app at a time. A stale setup lock left by a crashed process on the same machine is recovered automatically. If setup was interrupted on another machine sharing the directory, remove .linguana/cli.lock and retry.

Next.js apps

The CLI does not recognize Next.js yet. In a Next.js app, link detects React, writes the same variables, and prints Vite instructions that do not apply. doctor reports its SDK and Vite checks as failing.

You can still use link to create a project and a development build token:

terminal
npx @linguanahq/cli link --framework react --new-project "My Next.js app"

Then read the values in next.config.ts as shown in the Next.js guide. Next.js loads .env.local and, for production builds, .env.production.local before it evaluates next.config.ts. It does not load .env.staging.local; set staging values in your build host instead. The VITE_ names are only names in Next.js and are not exposed to the browser automatically.

Did this page get you to a working result?

On this page

No Headings