tsx é uma ferramenta para executar TypeScript diretamente no Node.js durante desenvolvimento, scripts e automações. Ela transforma o código em tempo de execução, entende ESM e CommonJS, oferece modo watch e procura tornar a experiência semelhante ao comando node. O foco é velocidade e simplicidade, não substituir o compilador TypeScript em todas as etapas.
Em vez de executar tsc, gravar JavaScript em dist e só então iniciar a aplicação, você pode rodar um arquivo .ts imediatamente. Isso acelera ciclos locais, ferramentas de linha de comando, migrations e testes rápidos.
Instalação
npm install -D tsx typescriptAdicione scripts:
{
"scripts": {
"dev": "tsx watch src/server.ts",
"start:local": "tsx src/server.ts",
"typecheck": "tsc --noEmit"
}
}Mantenha typescript instalado mesmo que tsx faça a transformação. A verificação de tipos continua sendo responsabilidade do TypeScript.
Executando um arquivo TypeScript
npx tsx src/server.tsArgumentos após o arquivo são repassados ao programa:
npx tsx scripts/importar.ts --arquivo clientes.csv --limite 500No código, leia com process.argv ou uma biblioteca de CLI.
Modo watch
Para reiniciar quando arquivos mudarem:
npx tsx watch src/server.tsO modo watch é útil em APIs e workers. Ele monitora dependências importadas e reinicia o processo quando detecta alterações.
Em desenvolvimento, trate sinais e encerre recursos corretamente. Uma reinicialização não deve deixar conexões, portas ou processos filhos presos.
import { createServer } from 'node:http';
const server = createServer((_req, res) => {
res.end('ok');
});
server.listen(3000);
async function shutdown(signal: string) {
console.log(`Recebido ${signal}`);
server.close((error) => {
if (error) {
console.error(error);
process.exitCode = 1;
}
});
}
process.on('SIGINT', () => shutdown('SIGINT'));
process.on('SIGTERM', () => shutdown('SIGTERM'));tsx não faz type checking
Ferramentas rápidas de transformação normalmente removem os tipos e executam o JavaScript resultante. Elas não analisam todo o programa como tsc. Um erro de tipo pode passar pelo tsx e causar problema em runtime.
Mantenha um script separado:
npm run typecheckEm CI:
- run: npm ci
- run: npm run typecheck
- run: npm test
- run: npm run buildConfiguração do tsconfig.json
Uma base moderna:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"noUncheckedIndexedAccess": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true,
"types": ["node"]
},
"include": ["src", "scripts", "test"]
}Ajuste module e moduleResolution à estratégia do projeto. Não copie uma configuração sem entender se o pacote usa ESM, CommonJS ou produz uma biblioteca.
ESM com tsx
Defina no package.json:
{
"type": "module"
}Então use imports:
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
const arquivo = join(process.cwd(), 'config.json');
const conteudo = await readFile(arquivo, 'utf8');
console.log(conteudo);Top-level await pode ser usado quando o arquivo é tratado como ESM. Em bibliotecas, considere compatibilidade dos consumidores.
CommonJS
tsx também atende projetos CommonJS. Um pacote sem type: module pode usar a semântica correspondente. Porém, misturar formatos sem convenção causa erros difíceis. Use extensões .mts, .cts, .mjs e .cjs quando precisar tornar a intenção explícita.
Executando com flags do Node.js
tsx procura manter compatibilidade com opções do Node. Para habilitar source maps ou inspeção, use:
node --import tsx --inspect src/server.tsEssa forma é útil quando outra ferramenta chama node diretamente e permite registrar tsx por --import.
Depuração
No VS Code, uma configuração pode usar o executável tsx:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "API com tsx",
"runtimeExecutable": "node",
"runtimeArgs": ["--import", "tsx"],
"program": "${workspaceFolder}/src/server.ts",
"skipFiles": ["/**"]
}
]
} Confirme que source maps apontam corretamente para TypeScript. Breakpoints devem ser colocados no arquivo fonte.
Scripts administrativos
tsx é adequado para scripts internos:
import { parseArgs } from 'node:util';
const { values } = parseArgs({
options: {
dryRun: { type: 'boolean', default: true },
limite: { type: 'string' },
},
});
const limite = Number(values.limite ?? 100);
if (!Number.isInteger(limite) || limite <= 0) {
throw new Error('Limite inválido');
}
console.log({ dryRun: values.dryRun, limite });Mesmo scripts temporários precisam de validação, logs e modo dry-run quando modificam dados.
Migrations e seeds
Configure:
{
"scripts": {
"db:migrate": "tsx scripts/migrate.ts",
"db:seed": "tsx scripts/seed.ts"
}
}Garanta idempotência. Uma migration não deve depender apenas de ter sido executada uma vez; registre versão e transação no banco.
Carregamento de variáveis
Node.js moderno pode carregar arquivos de ambiente:
node --env-file=.env --import tsx src/server.tsNão versiona segredos. Use arquivos locais, gerenciadores de secrets ou variáveis fornecidas pelo ambiente.
Aliases de caminho
Aliases em tsconfig.json podem funcionar em algumas ferramentas, mas não substituem a resolução real de pacotes. Para aplicações simples:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@app/*": ["src/*"]
}
}
}Antes de usar, confirme o comportamento em desenvolvimento, testes e build de produção. Em pacotes publicados, prefira exports, imports e workspaces.
Testes
Node Test Runner pode executar TypeScript com registro de tsx:
node --import tsx --test "test/**/*.test.ts"No package.json:
{
"scripts": {
"test": "node --import tsx --test 'test/**/*.test.ts'"
}
}Use aspas compatíveis com o shell do CI ou uma biblioteca para glob multiplataforma.
tsx em produção
É possível executar TypeScript diretamente, mas a decisão precisa considerar:
- tempo de inicialização;
- dependências de desenvolvimento na imagem;
- superfície de ataque;
- previsibilidade do artefato;
- observabilidade e source maps;
- política de deploy.
Para serviços de longa duração, compilar antes do deploy geralmente produz uma imagem menor e um artefato imutável. tsx é excelente no desenvolvimento e em ferramentas internas, enquanto produção pode executar JavaScript gerado.
Build separado
Uma estratégia comum:
{
"scripts": {
"dev": "tsx watch src/server.ts",
"typecheck": "tsc --noEmit",
"build": "tsc -p tsconfig.build.json",
"start": "node dist/server.js"
}
}O fluxo local continua rápido e o deploy usa arquivos compilados.
Docker
FROM node:24-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run typecheck && npm run build
FROM node:24-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
CMD ["node", "dist/server.js"]tsx fica apenas na etapa de desenvolvimento/build.
Comparação com ts-node
tsx costuma priorizar inicialização rápida e configuração pequena. ts-node oferece integração mais direta com o compilador TypeScript e pode ser necessário em fluxos que dependem de comportamento específico do tsc. A escolha deve ser feita por testes no projeto, não apenas por benchmark genérico.
Segurança da cadeia de ferramentas
Fixe tsx e TypeScript no lockfile, use npm ci, revise atualizações e execute auditorias. Ferramentas de runtime recebem acesso ao código, sistema de arquivos e variáveis do processo.
Fluxo recomendado
Use tsx para desenvolvimento, scripts, testes e protótipos. Mantenha tsc --noEmit obrigatório, configure sinais, valide aliases e produza um build explícito para serviços críticos. Combine com ESLint Flat Config no Node.js, formatação em Prettier no Node.js, pacotes em Exports e Imports no Node.js e testes em Node Test Runner.
Consulte o repositório oficial do tsx e a referência oficial do TSConfig.



