App-as-Code

Aplikacje z kodu: SST vs Encore

Lubię takie porównania, bo dwa narzędzia obiecują dokładnie to samo, a pod maską są zupełnie inne. Obie platformy mówią: opisujesz aplikację w kodzie, a one ogarniają infrastrukturę pod spodem. Różni je jednak coś fundamentalnego — skąd bierze się wiedza o tym, jaka infrastruktura jest potrzebna. SST każe Ci ją zadeklarować (elastycznie, jak w klasycznym IaC), Encore wywodzi ją z Twojego kodu aplikacji (przez analizę statyczną). To pozornie drobne rozróżnienie pociąga za sobą całą resztę: język, lock-in, sposób pracy lokalnej i to, ile decyzji musisz podjąć.

Oś sporu

SST = konfiguracja: ty komponujesz zasoby z bloczków IaC. Encore = konwencja: framework czyta kod i sam dokłada infrastrukturę.

Czym jest SST

SST to framework do budowy i wdrażania pełnych aplikacji (frontend + backend + infrastruktura) — głównie na AWS. W wersji 3 jego silnikiem jest Pulumi z providerami Terraform, więc pod maską masz pełną moc klasycznego IaC: setki providerów i zasobów. Na wierzchu dostajesz wysokopoziomowe komponenty (sst.aws.Function, sst.aws.Bucket, sst.aws.Astro itd.), które ukrywają boilerplate, oraz mechanizm link, który automatycznie przekazuje uprawnienia i zmienne między zasobami.

Aplikację opisujesz w sst.config.ts — zwykłym TypeScript, z pętlami, warunkami i pakietami:

// sst.config.ts
export default $config({
  app: () => ({ name: "eiac", home: "aws" }),
  async run() {
    const bucket = new sst.aws.Bucket("Assets");

    const api = new sst.aws.Function("Api", {
      handler: "src/api.handler",
      url: true,
      link: [bucket], // nadaje funkcji dostęp do bucketa (IAM + env)
    });

    new sst.aws.Astro("Web", { link: [api] });

    return { api: api.url };
  },
});

Sygnaturą SST jest tryb sst dev — uruchamia lokalną pętlę developerską, w której kod funkcji działa na Twojej maszynie, ale jest wpięty w prawdziwe zasoby w chmurze (tzw. Live Lambda). Dostajesz natychmiastowy feedback bez ciągłego deployu.

npx sst dev      # lokalny dev wpięty w realne zasoby w chmurze
npx sst deploy --stage production

Kluczowe cechy modelu SST:

  • Pełen IaC pod spodem — przez Pulumi/Terraform sięgniesz po dowolny zasób (kolejki, bazy, DNS, Cloudflare), nie tylko gotowe komponenty.
  • Frontend i backend razem — komponenty dla Next/Astro/React Router wdrażasz obok API w jednym repo.
  • link zamiast ręcznego IAM — relacje między zasobami zamiast ręcznego klejenia uprawnień i zmiennych.
  • Stan i etapy (stages) — odseparowane środowiska (--stage), stan trzymany jak w Pulumi.

Czym jest Encore

Encore odwraca kierunek. Zamiast deklarować infrastrukturę, deklarujesz elementy aplikacji — serwisy, endpointy, bazy, kolejki, crony — jako konstrukcje w kodzie (TypeScript lub Go). Encore analizuje ten kod statycznie, buduje graf aplikacji i sam provisionuje potrzebne zasoby: lokalnie, a po wdrożeniu w chmurze. Infrastruktury nie opisujesz osobno — ona „wynika” z tego, czego użyłeś.

// api.ts — serwis, endpoint i baza wywiedzione z kodu
import { api } from "encore.dev/api";
import { SQLDatabase } from "encore.dev/storage/sqldb";

const db = new SQLDatabase("catalog", { migrations: "./migrations" });

export const getTool = api(
  { method: "GET", path: "/tools/:id", expose: true },
  async ({ id }: { id: string }) => {
    const row = await db.queryRow`SELECT name FROM tools WHERE id = ${id}`;
    return { tool: row?.name };
  },
);

Z deklaracji new SQLDatabase(...) Encore wie, że potrzebna jest baza — i tworzy ją sam (lokalnie w kontenerze, w chmurze jako zarządzaną instancję). Wywołania między serwisami są typowane: importujesz funkcję innego serwisu i wołasz ją jak zwykłą, a Encore zamienia to w wywołanie sieciowe z zachowaniem typów.

Drugą sygnaturą Encore jest lokalny dashboard: encore run startuje aplikację z rozproszonym tracingiem, eksploratorem API i automatyczną dokumentacją — bez konfiguracji.

encore run        # lokalnie: dashboard, tracing, API explorer
encore deploy     # wdrożenie (Encore Cloud) ...
encore build docker eiac:latest   # ... albo własny obraz do self-hostingu

Wdrożenie ma dwie drogi: Encore Cloud automatycznie provisionuje aplikację na Twoim koncie AWS/GCP (i daje CI/CD, środowiska, podgląd), albo budujesz samodzielny obraz Dockera (encore build) i uruchamiasz go gdziekolwiek, np. na Kubernetes.

Kluczowe cechy modelu Encore:

  • Infrastruktura z kodu — brak osobnego IaC; zasoby wynikają z użytych prymitywów.
  • Konwencja zamiast konfiguracji — mniej „kleju”, więcej narzuconej struktury.
  • Wbudowana obserwowalność — tracing, metryki, dokumentacja API od ręki.
  • Bezpieczne wywołania między serwisami — typowane, sprawdzane w czasie kompilacji.

Filozofia: konfiguracja kontra konwencja

To jest sedno różnicy. W SST infrastruktura jest jawna i programowalna — masz nad nią pełną kontrolę, ale też pełną odpowiedzialność: to Ty decydujesz, jaki zasób powołać i jak go połączyć. W Encore infrastruktura jest domniemana — framework wie, czego potrzebujesz, bo przeczytał Twój kod; płacisz za to dopasowaniem się do jego modelu.

Z tego wypływają wszystkie praktyczne konsekwencje: elastyczność kontra prostota, brak lock-inu na runtime kontra wbudowane „baterie”, krzywa wejścia po stronie infrastruktury kontra krzywa wejścia po stronie konwencji frameworka.

Te same zadania, dwa style

Spójrz na to samo zadanie — API z dostępem do magazynu danych — w obu narzędziach.

W SST najpierw deklarujesz zasób (Bucket), potem jawnie łączysz go z funkcją (link), a uprawnienia IAM i zmienne środowiskowe wygeneruje framework:

const bucket = new sst.aws.Bucket("Assets");
new sst.aws.Function("Api", { handler: "src/api.handler", link: [bucket] });

W Encore po prostu używasz prymitywu w kodzie — sama jego obecność „zamawia” infrastrukturę:

const bucket = new Bucket("assets", { public: false });
// użycie bucket.upload(...) w endpointcie wystarcza, by Encore go zapewnił

Różnica nie jest składniowa, lecz koncepcyjna: w SST infrastruktura to osobny, jawny obiekt; w Encore to efekt uboczny użycia API.

Różnice w kluczowych wymiarach

WymiarSSTEncore
Model infrastrukturydeklarowana jawnie (komponenty)wywiedziona z kodu (analiza statyczna)
Pod maskąPulumi + providerzy Terraformwłasny runtime + generowane IaC
JęzykiTypeScript/JavaScriptTypeScript i Go
ChmuraAWS-first (też Cloudflare i inne)AWS/GCP (Encore Cloud) lub własny obraz
Frontendtak (Next/Astro/React…)nie (backend-first)
Lokalny DXsst dev (Live Lambda, realne zasoby)encore run (dashboard, tracing, API explorer)
Obserwowalnośćdokładasz samwbudowana
Elastyczność infrybardzo wysoka (cały IaC)ograniczona do modelu frameworka
Lock-inna AWS/komponenty, nie na runtimena model i runtime Encore
Wyjście awaryjnenaturalne (dropniesz do surowego IaC)węższe (poza modelem trudniej)

Wady i zalety

SST

Zalety

  • Pełna moc IaC — sięgniesz po dowolny zasób przez Pulumi/Terraform, nie tylko gotowce.
  • Frontend + backend + infrastruktura w jednym repo i jednym wdrożeniu.
  • link realnie redukuje boilerplate IAM i konfiguracji.
  • Brak narzuconego runtime — Twój kod to zwykłe funkcje; mniejszy lock-in na sposób pisania.
  • Świetny lokalny feedback (Live Lambda).

Wady

  • AWS-centryczny — najlepiej działa na AWS; poza nim wsparcie jest węższe.
  • Więcej decyzji i wiedzy o infrastrukturze po Twojej stronie.
  • Trzeba zarządzać stanem i etapami (jak w Pulumi).
  • Obserwowalność i konwencje musisz sobie poskładać sam.

Encore

Zalety

  • Minimum boilerplate — infrastruktura wynika z kodu, bez osobnego IaC.
  • Wbudowana obserwowalność (tracing, metryki, dokumentacja API) od pierwszej minuty.
  • Typowane, bezpieczne wywołania między serwisami.
  • Spójna struktura w zespole dzięki konwencji.
  • Elastyczne wdrożenie: Encore Cloud albo własny obraz Dockera.

Wady

  • Lock-in na model i runtime Encore — wychodzisz poza schemat z trudem.
  • Ograniczona elastyczność dla nietypowej infrastruktury.
  • Tylko Go i TypeScript.
  • Mniejszy ekosystem i społeczność niż wokół Pulumi/Terraform.
  • „Magia” analizy statycznej bywa trudniejsza do debugowania, gdy coś nie zadziała.

Kiedy co wybrać

  • Wybierz SST, gdy potrzebujesz pełnej kontroli nad infrastrukturą AWS, chcesz wdrażać frontend razem z backendem albo sięgać po zasoby spoza „happy path” (kolejki, nietypowe usługi, multi-provider). Cena: więcej decyzji i wiedzy o IaC.
  • Wybierz Encore, gdy budujesz backend/mikroserwisy i zależy Ci na maksymalnej prostocie, wbudowanej obserwowalności i szybkim starcie — a akceptujesz związanie z modelem frameworka. Cena: mniej elastyczności i lock-in na runtime.

Dobry papierek lakmusowy: jeśli najwięcej czasu spędzasz na infrastrukturze i chcesz nią rządzić — SST. Jeśli najwięcej czasu spędzasz na logice biznesowej i chcesz, żeby infrastruktura „po prostu była” — Encore.

Podsumowanie

SST i Encore rozwiązują ten sam problem z dwóch przeciwnych stron. SST to elastyczny framework IaC z wysokopoziomowymi komponentami: dużo mocy, dużo kontroli, AWS w centrum. Encore to opinionowany framework backendowy, który infrastrukturę wywodzi z kodu i dorzuca obserwowalność: mało boilerplate’u, szybki start, w zamian za życie wewnątrz jego modelu.

Wybór sprowadza się do jednego pytania: czy chcesz rządzić infrastrukturą, czy chcesz o niej zapomnieć. Obie odpowiedzi są poprawne — pod warunkiem, że świadomie zaakceptujesz ich konsekwencje. U mnie? Zależy od projektu: do szybkiego backendu sięgam po Encore, do czegoś, co muszę wyrzeźbić po swojemu — po SST. Weź oba na warsztat na jednym weekendowym projekcie, różnicę poczujesz w pięć minut. :)