Voltar para o Blog

Bun 1.2: O Runtime JavaScript Que Esta Quebrando Recordes de Performance

Ola HaWkers, se voce acompanha o ecossistema JavaScript, provavelmente ja ouviu falar do Bun. Esse runtime relativamente novo esta conquistando desenvolvedores com numeros de performance impressionantes.

Voce ja se frustrou esperando o npm install terminar? Ou talvez tenha sentido que seu servidor Node.js poderia ser mais rapido? O Bun promete resolver esses problemas e muito mais.

O Que e o Bun

O Bun e um runtime JavaScript e toolkit tudo-em-um que inclui:

Componentes Principais:

  • Runtime JavaScript (alternativa ao Node.js)
  • Package manager (alternativa ao npm/yarn/pnpm)
  • Bundler (alternativa ao webpack/esbuild)
  • Test runner (alternativa ao Jest/Vitest)
  • TypeScript transpiler nativo

O diferencial? Tudo isso foi escrito em Zig e C++ para maxima performance, usando o JavaScriptCore (motor do Safari) em vez do V8.

Novidades do Bun 1.2

Windows Nativo

Finalmente, suporte completo ao Windows:

# Instalacao no Windows (PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"

# Ou via npm
npm install -g bun

# Verificar instalacao
bun --version
# 1.2.0

Antes da versao 1.2, o Bun no Windows dependia do WSL. Agora funciona nativamente.

S3 Object Storage Nativo

O Bun 1.2 introduziu APIs nativas para Amazon S3:

// Acesso nativo ao S3 - sem SDKs pesadas
import { S3Client } from "bun";

const s3 = new S3Client({
  accessKeyId: Bun.env.AWS_ACCESS_KEY_ID,
  secretAccessKey: Bun.env.AWS_SECRET_ACCESS_KEY,
  region: "us-east-1"
});

// Upload de arquivo
const file = Bun.file("./image.png");
await s3.write("my-bucket/image.png", file);

// Download
const downloaded = await s3.file("my-bucket/image.png");
await Bun.write("./downloaded.png", downloaded);

// Streaming de arquivos grandes
const stream = s3.file("my-bucket/large-video.mp4").stream();

Postgres Nativo

Driver PostgreSQL integrado ao runtime:

// Sem instalar pg ou postgres.js
import { SQL } from "bun";

const sql = new SQL({
  hostname: "localhost",
  database: "myapp",
  username: "user",
  password: "password"
});

// Queries com tagged templates
const users = await sql`SELECT * FROM users WHERE active = true`;

// Queries parametrizadas (seguras contra SQL injection)
const userId = 123;
const user = await sql`SELECT * FROM users WHERE id = ${userId}`;

// Transacoes
await sql.begin(async (tx) => {
  await tx`UPDATE accounts SET balance = balance - 100 WHERE id = 1`;
  await tx`UPDATE accounts SET balance = balance + 100 WHERE id = 2`;
});

Performance Comparada

Package Manager

Vamos comparar instalacao de dependencias:

# Projeto com ~50 dependencias

# npm
time npm install
# real: 45.2s

# yarn
time yarn install
# real: 32.1s

# pnpm
time pnpm install
# real: 18.7s

# bun
time bun install
# real: 2.3s

O Bun e consistentemente 10-20x mais rapido que npm.

Runtime Performance

Servidor HTTP:

// Bun native server
Bun.serve({
  port: 3000,
  fetch(req) {
    return new Response("Hello World");
  }
});

// Resultados: ~185,000 req/s

Comparativo de requisicoes por segundo:

Runtime Hello World JSON API File Serve
Bun 1.2 185,000 142,000 78,000
Deno 2.0 125,000 95,000 45,000
Node 22 118,000 88,000 52,000

Bundler

# Build de projeto React grande (~500 componentes)

# webpack
time npx webpack build
# real: 28.4s

# esbuild
time npx esbuild src/index.tsx --bundle --outdir=dist
# real: 0.8s

# bun
time bun build src/index.tsx --outdir=dist
# real: 0.4s

Usando Bun na Pratica

Criando um Projeto

# Criar projeto
mkdir meu-projeto && cd meu-projeto
bun init

# Estrutura criada:
# meu-projeto/
#   .gitignore
#   bun.lockb
#   index.ts
#   package.json
#   README.md
#   tsconfig.json

Servidor Web Completo

// server.ts
import { Hono } from "hono";
import { cors } from "hono/cors";
import { logger } from "hono/logger";

const app = new Hono();

// Middlewares
app.use("*", logger());
app.use("/api/*", cors());

// Database connection (nativo do Bun)
const db = new SQL({
  hostname: Bun.env.DB_HOST,
  database: Bun.env.DB_NAME,
  username: Bun.env.DB_USER,
  password: Bun.env.DB_PASSWORD
});

// Routes
app.get("/", (c) => c.text("Hello Bun!"));

app.get("/api/users", async (c) => {
  const users = await db`SELECT id, name, email FROM users`;
  return c.json(users);
});

app.post("/api/users", async (c) => {
  const body = await c.req.json();
  const { name, email } = body;

  const [user] = await db`
    INSERT INTO users (name, email)
    VALUES (${name}, ${email})
    RETURNING *
  `;

  return c.json(user, 201);
});

// File uploads (com S3 nativo)
app.post("/api/upload", async (c) => {
  const form = await c.req.formData();
  const file = form.get("file") as File;

  const s3 = new S3Client({
    accessKeyId: Bun.env.AWS_ACCESS_KEY_ID!,
    secretAccessKey: Bun.env.AWS_SECRET_ACCESS_KEY!,
    region: "us-east-1"
  });

  const key = `uploads/${Date.now()}-${file.name}`;
  await s3.write(`my-bucket/${key}`, file);

  return c.json({ url: `https://my-bucket.s3.amazonaws.com/${key}` });
});

export default {
  port: 3000,
  fetch: app.fetch
};

Executar e Desenvolver

# Rodar em desenvolvimento (com hot reload)
bun --watch run server.ts

# Rodar em producao
bun run server.ts

# Scripts do package.json
bun run dev
bun run build
bun run test

Sistema de Testes

O Bun tem test runner integrado compativel com Jest:

// math.ts
export function add(a: number, b: number): number {
  return a + b;
}

export function multiply(a: number, b: number): number {
  return a * b;
}

export async function fetchUser(id: number) {
  const response = await fetch(`https://api.example.com/users/${id}`);
  return response.json();
}
// math.test.ts
import { describe, test, expect, mock, beforeEach } from "bun:test";
import { add, multiply, fetchUser } from "./math";

describe("Math functions", () => {
  test("add should sum two numbers", () => {
    expect(add(2, 3)).toBe(5);
    expect(add(-1, 1)).toBe(0);
  });

  test("multiply should multiply two numbers", () => {
    expect(multiply(3, 4)).toBe(12);
    expect(multiply(0, 100)).toBe(0);
  });
});

describe("API functions", () => {
  beforeEach(() => {
    // Mock do fetch global
    global.fetch = mock(async (url: string) => {
      return new Response(JSON.stringify({
        id: 1,
        name: "Test User"
      }));
    });
  });

  test("fetchUser should return user data", async () => {
    const user = await fetchUser(1);
    expect(user.name).toBe("Test User");
  });
});
# Rodar testes
bun test

# Com coverage
bun test --coverage

# Watch mode
bun test --watch

# Filtrar testes
bun test --filter "Math"

Bundler Integrado

// bun.config.ts (opcional)
export default {
  entrypoints: ["./src/index.tsx"],
  outdir: "./dist",
  target: "browser",
  minify: true,
  sourcemap: "external",
  splitting: true,
  plugins: [
    // Plugins customizados
  ]
};
# Build simples
bun build ./src/index.tsx --outdir ./dist

# Build com minificacao
bun build ./src/index.tsx --outdir ./dist --minify

# Build para Node.js
bun build ./src/server.ts --outdir ./dist --target node

# Watch mode
bun build ./src/index.tsx --outdir ./dist --watch

Macros em Tempo de Build

Uma feature unica do Bun sao macros que rodam em tempo de compilacao:

// config.ts
export const VERSION = await Bun.file("./version.txt").text();
export const BUILD_TIME = new Date().toISOString();

// Isso e avaliado em tempo de build, nao em runtime!
export const ENV_CONFIG = {
  apiUrl: Bun.env.API_URL,
  debug: Bun.env.DEBUG === "true"
};
// app.ts
import { VERSION, BUILD_TIME } from "./config" with { type: "macro" };

console.log(`Version: ${VERSION}`);
console.log(`Built at: ${BUILD_TIME}`);

// No bundle final, esses valores sao substituidos por strings literais

Compatibilidade com Node.js

O Bun e altamente compativel com Node.js:

// A maioria do codigo Node.js funciona sem mudancas
import express from "express";
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcrypt";

const app = express();
const prisma = new PrismaClient();

app.use(express.json());

app.post("/login", async (req, res) => {
  const { email, password } = req.body;

  const user = await prisma.user.findUnique({
    where: { email }
  });

  if (!user) {
    return res.status(401).json({ error: "User not found" });
  }

  const valid = await bcrypt.compare(password, user.password);

  if (!valid) {
    return res.status(401).json({ error: "Invalid password" });
  }

  res.json({ user: { id: user.id, email: user.email } });
});

// Funciona com bun run ou node
app.listen(3000);

APIs Node.js Suportadas

// Maioria das APIs Node.js funcionam
import fs from "fs";
import path from "path";
import crypto from "crypto";
import { Buffer } from "buffer";
import { EventEmitter } from "events";
import { Readable, Writable } from "stream";

// process global
console.log(process.env.NODE_ENV);
console.log(process.cwd());

// APIs Bun adicionais
const file = Bun.file("./data.json");
const content = await file.text();

const hash = Bun.hash("sha256", "data");

Quando Usar Bun

Casos Ideais

1. Projetos Novos que Precisam de Performance:

// APIs de alta performance
// Processamento de dados em tempo real
// Servidores de WebSocket
// Microservicos

Bun.serve({
  port: 3000,
  websocket: {
    message(ws, message) {
      // Broadcast para todos os clientes
      server.publish("chat", message);
    }
  },
  fetch(req, server) {
    if (server.upgrade(req)) {
      return; // Upgrade para WebSocket
    }
    return new Response("Hello!");
  }
});

2. Scripts e Ferramentas CLI:

#!/usr/bin/env bun

// Script de migracao de dados
import { SQL } from "bun";

const sourceDb = new SQL({ /* config fonte */ });
const targetDb = new SQL({ /* config destino */ });

console.log("Starting migration...");

const users = await sourceDb`SELECT * FROM users`;

for (const user of users) {
  await targetDb`
    INSERT INTO users (id, name, email)
    VALUES (${user.id}, ${user.name}, ${user.email})
  `;
  console.log(`Migrated user ${user.id}`);
}

console.log(`Migration complete! ${users.length} users migrated.`);

3. Quando Tempo de Build Importa:

# CI/CD mais rapido
# bun install + bun build em segundos
# vs npm install + webpack em minutos

Quando Evitar (Por Enquanto)

  • Projetos que dependem de native addons complexos
  • Ecossistemas muito especificos de Node.js
  • Quando estabilidade e mais importante que performance
  • Times que nao podem absorver curva de aprendizado

Migrando de Node.js

Passo 1: Instalar Bun

# Unix/Mac
curl -fsSL https://bun.sh/install | bash

# Windows
powershell -c "irm bun.sh/install.ps1 | iex"

Passo 2: Converter package.json

# Remover node_modules e lockfiles antigos
rm -rf node_modules package-lock.json yarn.lock pnpm-lock.yaml

# Instalar com Bun
bun install
# Cria bun.lockb

Passo 3: Testar Compatibilidade

# Rodar testes
bun test

# Rodar aplicacao
bun run dev

# Verificar se tudo funciona

Passo 4: Otimizar para Bun

// Substituir pacotes por APIs nativas quando possivel

// Antes: pg ou postgres.js
import { Client } from "pg";

// Depois: SQL nativo do Bun
import { SQL } from "bun";

// Antes: aws-sdk para S3
import AWS from "aws-sdk";

// Depois: S3 nativo do Bun
import { S3Client } from "bun";

Conclusao

O Bun 1.2 representa um avanco significativo no ecossistema JavaScript. Com performance impressionante, APIs nativas para tarefas comuns, e excelente compatibilidade com Node.js, esta se tornando uma opcao cada vez mais viavel para projetos serios.

A principal recomendacao e: experimente. Comece com um projeto novo ou um script, e va expandindo conforme ganhar confianca. O ecossistema Bun ainda esta amadurecendo, mas a direcao e promissora.

Se voce quer comparar Bun com outras opcoes de runtime, recomendo que de uma olhada em outro artigo: Deno 2.0 vs Node.js: A Batalha dos Runtimes onde voce vai descobrir como cada runtime se posiciona no mercado atual.

Bora pra cima! 🦅

Comentários (0)

Esse artigo ainda não possui comentários 😢. Seja o primeiro! 🚀🦅

Adicionar comentário