# node: Node.js Quickstart
URL: https://generaltranslation.com/en-US/docs/node/tutorials/quickstart.mdx
---
title: Node.js Quickstart
description: Add multiple languages to your Node.js server in under 10 minutes
---
By the end of this guide, your Node.js server will respond with translated content based on the request's language, using either inline or pre-registered strings.
**Prerequisites:**
- A Node.js server (Express, Fastify, or similar)
- Node.js 18+
**Want automatic setup?** Run `npx gt@latest` to configure everything with the [Setup Wizard](/docs/cli/init). This guide covers manual setup.
---
## Step 1: Install the packages
`gt-node` is the library that powers translations in your server. `gt` is the CLI tool that prepares translations for production.
```bash
npm i gt-node
npm i -D gt
```
```bash
yarn add gt-node
yarn add --dev gt
```
```bash
bun add gt-node
bun add --dev gt
```
```bash
pnpm add gt-node
pnpm add --save-dev gt
```
---
## Step 2: Create a translation config file
Create a **`gt.config.json`** file in your project root. This tells the library which languages you support:
```json title="gt.config.json"
{
"defaultLocale": "en",
"locales": ["es", "fr", "ja"]
}
```
- **`defaultLocale`** — the language your server's strings are written in.
- **`locales`** — the languages you want to translate into. Pick any from the [supported locales list](/docs/platform/supported-locales).
---
## Step 3: Initialize General Translation
Call **`initializeGT`** once at the top of your server's entry file, before any translation functions are used:
```js title="server.js"
import { initializeGT } from 'gt-node';
initializeGT({
defaultLocale: 'en',
locales: ['en', 'es', 'fr', 'ja'],
projectId: process.env.GT_PROJECT_ID,
});
```
This configures the library with your supported languages and project credentials.
---
## Step 4: Set locale context per request
Each request needs to know which language to use. Use **`withGT`** to wrap your request handlers — it uses async local storage so translation functions automatically pick up the right locale:
```js title="server.js"
import { withGT } from 'gt-node';
app.use((req, res, next) => {
const locale = req.headers['accept-language']?.split(',')[0] || 'en';
withGT(locale, () => next());
});
```
---
## Step 5: Translate inline strings
For translating strings directly inside request handlers, use **`getGT`**:
```js title="server.js"
import { getGT } from 'gt-node';
app.get('/api/greeting', async (req, res) => {
const gt = await getGT();
res.json({
message: gt('Hello, world!'),
welcome: gt('Welcome, {name}!', { name: 'Alice' }),
});
});
```
`getGT` returns a translation function scoped to the current request's locale.
---
## Step 6: Pre-register constant strings (optional)
For strings defined outside request handlers — like error messages, enum labels, or constants — use **`msg`** to register them at module scope, then **`getMessages`** to resolve translations at runtime:
```js title="messages.js"
import { msg } from 'gt-node';
export const GREETING = msg('Hello, world!');
export const WELCOME = msg('Welcome, {name}!');
export const NOT_FOUND = msg('Resource not found.');
```
```js title="handler.js"
import { getMessages } from 'gt-node';
import { GREETING, WELCOME, NOT_FOUND } from './messages.js';
app.get('/api/status', async (req, res) => {
const m = await getMessages();
res.json({
greeting: m(GREETING),
welcome: m(WELCOME, { name: 'Alice' }),
});
});
app.use(async (req, res) => {
const m = await getMessages();
res.status(404).json({ error: m(NOT_FOUND) });
});
```
This pattern is useful when the same strings are used across multiple handlers.
---
## Step 7: Set up environment variables (optional)
To see translations in development, you need API keys from General Translation. These enable **on-demand translation** — your server translates content in real time as you develop.
Create a **`.env`** file:
```bash title=".env"
GT_API_KEY="your-api-key"
GT_PROJECT_ID="your-project-id"
```
Get your free keys at [dash.generaltranslation.com](https://dash.generaltranslation.com/signup) or by running:
```bash
npx gt auth
```
Never expose `GT_API_KEY` publicly or commit it to source control.
Yes. Without API keys, `gt-node` works as a standard i18n library. You won't get on-demand translation in development, but you can still:
- Provide your own translation files manually
- Use all translation functions (`getGT`, `msg`, `getMessages`, etc.)
- Run `npx gt generate` to create translation file templates, then translate them yourself
---
## Step 8: See it working
Start your server and test with different `Accept-Language` headers:
```bash
# Default (English)
curl http://localhost:3000/api/greeting
# Spanish
curl -H "Accept-Language: es" http://localhost:3000/api/greeting
# French
curl -H "Accept-Language: fr" http://localhost:3000/api/greeting
```
You should see translated responses for each language.
In development, translations happen on-demand — you may see a brief delay the first time a new language is requested. In production, translations are pre-generated and load instantly.
---
## Step 9: Full example
Here's a complete Express server with all the pieces together:
```js title="server.js"
import express from 'express';
import { initializeGT, withGT, getGT, msg, getMessages } from 'gt-node';
// Initialize GT before anything else
initializeGT({
defaultLocale: 'en',
locales: ['en', 'es', 'fr', 'ja'],
projectId: process.env.GT_PROJECT_ID,
});
// Pre-register constant strings
const NOT_FOUND = msg('Resource not found.');
const app = express();
// Set locale context for each request
app.use((req, res, next) => {
const locale = req.headers['accept-language']?.split(',')[0] || 'en';
withGT(locale, () => next());
});
// Inline translation
app.get('/api/greeting', async (req, res) => {
const gt = await getGT();
res.json({ message: gt('Hello, world!') });
});
// Pre-registered message translation
app.use(async (req, res) => {
const m = await getMessages();
res.status(404).json({ error: m(NOT_FOUND) });
});
app.listen(3000, () => console.log('Server running on port 3000'));
```
---
## Step 10: Deploy to production
In production, translations are pre-generated at build time (no real-time API calls). Add the translate command to your build script:
```json title="package.json"
{
"scripts": {
"build": "npx gt translate && "
}
}
```
Set your **production** environment variables in your hosting provider:
```bash
GT_PROJECT_ID=your-project-id
GT_API_KEY=gtx-api-your-production-key
```
Never publicly expose your `GT_API_KEY`.
That's it — your server is now multilingual. 🎉
---
## Troubleshooting
This is expected. In development, translations happen on-demand (your content is translated in real time via the API). This delay **does not exist in production** — all translations are pre-generated by `npx gt translate`.
Ambiguous text can lead to inaccurate translations. For example, "apple" could mean the fruit or the company. Add a `$context` option to help:
```js
gt('Apple', { $context: 'the technology company' });
```
Both `getGT()` and `msg()` support the `$context` option.
---
## Next steps
- [**`initializeGT`**](/docs/node/api/initialize-gt) — Full configuration options
- [**`withGT`**](/docs/node/api/with-gt) — Locale context for requests
- [**`getGT`**](/docs/node/api/get-gt) — Inline string translation
- [**`msg` & `getMessages`**](/docs/node/api/get-messages) — Pre-registered message translation
- [**CLI Tool**](/docs/cli/translate) — Translation workflow reference