Przejdź do treści

Dlaczego Twoja aplikacja działa lokalnie, ale nie na produkcji

Prawdziwe przyczyny i konkretne rozwiązania. AI optymalizuje pod działające demo, nie pod system produkcyjny. Przy 15–30 cichych decyzjach architektonicznych na każdy feature, każda z trafnością ~70%, szansa, że wszystkie są poprawne, jest praktycznie zerowa.

«Działa na mojej maszynie» to najstarszy żart w inżynierii oprogramowania. Ale przy aplikacjach generowanych przez AI to nie jest żart — to stan domyślny. AI nie myśli o produkcji. Nie wie, czym jest load balancer, connection pool czy secrets manager. Widzi tylko jedno: Twój lokalny kontekst, Twój plik, kod uruchomiony właśnie teraz na Twoim komputerze.

Kiedy AI buduje feature, podejmuje 15–30 cichych decyzji architektonicznych: jaka baza danych, jak łączyć się z API, gdzie trzymać klucze, jak obsługiwać błędy. Każda z tych decyzji ma mniej więcej 70% szans na bycie poprawną. Ale żeby cały feature działał na produkcji, wszystkie decyzje muszą być poprawne. Prawdopodobieństwo? Przy 20 decyzjach: 0.7^20 = 0.08%. Praktycznie zero.

Ten artykuł opisuje sześć najczęstszych powodów, dla których aplikacje AI działają lokalnie i padają na produkcji — z konkretnymi przykładami i rozwiązaniami. Jeśli budujesz z Cursor, Bolt, Lovable, Replit lub innym narzędziem AI, ten poradnik jest dla Ciebie.

Środowisko i konfiguracja

To najbardziej banalny i jednocześnie najczęstszy powód awarii na produkcji: konfiguracja, która działa tylko lokalnie. Twój plik .env na laptopie ma prawdziwe klucze API, poprawne URL-e, działające sekrety. Na produkcji? Placeholdery, brakujące zmienne, albo zupełnie inne adresy.

AI nigdy nie myśli o zarządzaniu konfiguracją — widzi tylko lokalny kontekst. Kiedy generuje kod, który łączy się z API, wpisuje http://localhost:3000 wprost w kodzie. Kiedy potrzebuje klucza API, tworzy zmienną z domyślną wartością. Kiedy buduje URL do bazy danych, hardcoduje string połączenia.

Typowe problemy:

  • Hardcoded URL-ehttp://localhost:3000/api zamiast zmiennej środowiskowej. Działa lokalnie, na produkcji prowadzi donikąd.
  • Brakujące zmienne środowiskowe — na produkcji nie masz pliku .env. Musisz ustawić zmienne w panelu hostingu (Vercel, Railway, Render).
  • HTTP vs HTTPS — lokalnie używasz http://, produkcja wymaga https://. Mieszanie protokołów powoduje blokowanie przez przeglądarkę (mixed content) i błędy CORS.
  • Różne klucze API — klucz testowy Stripe vs produkcyjny. Klucz dev Firebase vs prod. AI nie wie, że istnieje różnica.

Jak to naprawić

Wynieś CAŁĄ konfigurację poza kod. Każdy URL, każdy klucz, każdy sekret powinien pochodzić ze zmiennej środowiskowej — nigdy z kodu źródłowego. Użyj secrets managera (np. Doppler, AWS Secrets Manager, Vercel Environment Variables). Stwórz plik .env.example z nazwą każdej wymaganej zmiennej (bez wartości) i dodaj go do repozytorium jako dokumentację.

Założenia dotyczące bazy danych

AI kocha SQLite. Jest prosta, nie wymaga serwera, to tylko plik. Idealnie nadaje się do prototypu. Problem? Platformy serverless (Vercel, Netlify Functions, AWS Lambda) nie obsługują SQLite, bo każde zapytanie może trafić na inną instancję — nie ma współdzielonego systemu plików.

Ale baza danych to nie tylko silnik. To cały zestaw założeń, które AI robi cicho:

  • Brak indeksów — zapytanie działa błyskawicznie na 50 rekordach. Na 50 000? Trwa 30 sekund. AI nie dodaje indeksów, bo na małych danych nie widać różnicy.
  • Brak connection poolingu — każde zapytanie HTTP otwiera nowe połączenie z bazą. Przy 100 równoczesnych użytkownikach masz 100 otwartych połączeń. Baza danych ma limit — zwykle 20–100 połączeń. Po przekroczeniu: awaria.
  • Schemat, który wygląda dobrze w demo — brak relacji, brak constraintów, brak typów. Dane są niespójne, ale na 50 rekordach tego nie widać.
  • Brak migracji — AI tworzy tabele «w locie». Na produkcji nie możesz dropnąć bazy i stworzyć jej od nowa — masz prawdziwe dane użytkowników.

Jak to naprawić

Użyj PostgreSQL lub MySQL na produkcji. Skonfiguruj connection pooling (PgBouncer, Supabase ma to wbudowane). Dodaj indeksy na kolumnach używanych w WHERE i JOIN. Zaplanuj strategię migracji — użyj narzędzia jak Prisma Migrate, Drizzle, albo zwykłych plików SQL z wersjonowaniem. Nigdy nie modyfikuj schematu produkcyjnego ręcznie.

Bezpieczeństwo, które nie istnieje

Raport Veracode „2025 GenAI Code Security Report” wykazał, że modele LLM wprowadzały podatność z OWASP Top 10 w 45% przypadków testowych. Podobny wynik uzyskał ośrodek analityczny Georgetown CSET: niemal połowa przebadanych fragmentów kodu zawierała exploitable błędy. To nie jest marginalny problem. A kod, który «działa» na localhost, nie musi być bezpieczny.

Skan 5 600 aplikacji zbudowanych metodą vibecoding, wykonany przez Escape.tech, ujawnił ponad 2 000 luk o wysokim wpływie i ponad 400 ujawnionych sekretów. Platforma agentów Moltbook ujawniła 1,5 miliona tokenów API przez źle skonfigurowaną bazę Supabase bez skutecznego Row Level Security. A skan aplikacji zbudowanych w Lovable wykazał 170 projektów — około jeden na dziesięć przeanalizowanych — wystawiających swoje bazy danych przez brak RLS (CVE-2025-48757): każdy nieuwierzytelniony mógł czytać i modyfikować dowolne tabele.

Problemy, które widzę regularnie:

  • Klucze API hardcoded w JavaScript frontendu — każdy może otworzyć DevTools i je skopiować. Widziałem to wielokrotnie w aplikacjach klientów.
  • Brak walidacji inputów — SQL injection, XSS, path traversal — AI rzadko dodaje walidację, bo na localhost nikt nie próbuje włamać się do Twojej aplikacji.
  • Brak Row Level SecuritySupabase bez RLS oznacza, że każdy użytkownik może czytać i modyfikować dane wszystkich innych użytkowników.
  • Brak rate limitingu — bez ograniczeń ktoś może wywołać Twoje API milion razy na minutę. Efekt: ogromny rachunek za API, atak DDoS albo jedno i drugie.

Jak to naprawić

Przeprowadź audyt OWASP Top 10. Włącz Row Level Security na Supabase. Waliduj wszystkie inputy po stronie serwera (nigdy nie ufaj klientowi). Przeskanuj repozytorium pod kątem ujawnionych sekretów (użyj gitleaks lub trufflehog). Dodaj rate limiting na wszystkich publicznych endpointach. Przenieś klucze API z frontendu do backendu.

Ciche awarie i wycieki zasobów

Twoja aplikacja działa przez pierwsze 100 zapytań. Zapytanie numer 1 001 powoduje awarię — wszystkie połączenia z bazą są wyczerpane. Dlaczego? Bo AI nigdy nie zamknęło połączeń. Każde zapytanie otwierało nowe połączenie, ale żadne go nie zwalniało.

To samo dotyczy uchwytów plików, listenerów WebSocket, timerów i subskrypcji. AI tworzy zasoby, ale ich nie zwalnia. Na localhost nie widać tego, bo restartowanie serwera co kilka minut resetuje wszystko. Na produkcji serwer działa bez przerwy — i zasoby się kończą.

Jeszcze gorsze są ciche błędy:

  • Puste bloki try/catch — płatność nie przechodzi, webhook się nie uruchamia, ale użytkownik nie widzi żadnego błędu. Dane znikają po cichu.
  • Race conditions — wiele równoczesnych wywołań API kończy się w losowej kolejności. Brak idempotentności oznacza duplikaty lub niespójne dane.
  • Hot reload maskuje błędy — w trybie developerskim React wyświetla ostrzeżenia. W buildzie produkcyjnym znikają. Jeden komponent rzuca błąd — cała aplikacja bieleje, bo nie ma error boundaries.
  • Brak globalnego error handlera — nieobsłużony wyjątek zabija proces Node.js. Na localhost restartowanie jest natychmiastowe. Na produkcji — downtime.

Jak to naprawić

Dodaj error boundaries na frontendzie (React: ErrorBoundary). Dodaj globalny error handler na backendzie (process.on('uncaughtException')). Wdróż strukturalne logowanie (Sentry, LogRocket, Pino). Zamykaj połączenia z bazą po użyciu (albo użyj connection poolingu). Sprzątaj listenery i timery w useEffect cleanup. Testuj pod obciążeniem — nie wystarczy sprawdzić, że działa raz.

Prawdziwe szkody

To nie są teoretyczne zagrożenia. To incydenty, które już się wydarzyły:

  • Amazon — cztery incydenty Sev-1 w e-commerce w ciągu jednego tygodnia, w tym 6-godzinna awaria, którą wewnętrzne dokumenty wiązały z ok. 6,3 miliona utraconych zamówień. Relacje łączyły serię incydentów ze zmianami wspomaganymi GenAI; Amazon zaprzecza, by chodziło o kod napisany przez AI. Tak czy inaczej — nawet Amazon wprowadził dodatkowy przegląd zmian produkcyjnych wspieranych AI.
  • Niekontrolowane rachunki za chmurę — usługi prototypowane przez AI i wdrożone bez kontroli kosztów regularnie zaskakują swoich właścicieli. AI nie wie, że t3.micro kosztuje inaczej niż r5.4xlarge. Skalowanie kosztów to coś, o czym AI w ogóle nie myśli.
  • Integracje Stripe — handlery webhooków zbudowane na przestarzałych kształtach API trafiały do produkcji z podwójnymi naliczeniami, wykrywanymi dopiero po tygodniach.
  • Ankieta Final Round AI wśród 18 CTO — 16 z nich zgłosiło katastrofy produkcyjne bezpośrednio spowodowane kodem wygenerowanym przez AI.
  • Analiza CodeRabbit na 470 pull requestach open source — kod współtworzony przez AI miał ~1,7x więcej problemów ogółem, ok. 2,7x więcej podatności klasy XSS i ~8x więcej problemów wydajnościowych typu nadmierne operacje I/O niż kod pisany przez ludzi.

Wzorzec powtarza się: AI generuje kod, który wygląda dobrze. Przechodzi code review (bo jest czytelny). Przechodzi testy (bo testuje szczęśliwą ścieżkę). A potem wybucha na produkcji, bo nikt nie sprawdził wydajności pod obciążeniem, obsługi błędów, bezpieczeństwa ani kosztów infrastruktury.

Jak to naprawdę naprawić (checklista produkcyjna)

Zanim wdrożysz swoją aplikację, przejdź przez te punkty. Każdy niespełniony punkt to potencjalna awaria na produkcji. Ta checklista powstała na podstawie dziesiątek audytów aplikacji AI, które przeprowadziłem dla klientów.

  • Cała konfiguracja przez zmienne środowiskowe. Żadnych hardcoded URL-i, kluczy ani sekretów w kodzie źródłowym.
  • Produkcyjna baza danych z indeksami i connection poolingiem. Nie SQLite. PostgreSQL lub MySQL z PgBouncer lub wbudowanym poolerem.
  • HTTPS wszędzie, nagłówki bezpieczeństwa ustawione. Żadnego mieszania HTTP i HTTPS. CSP, HSTS, X-Frame-Options.
  • Row Level Security / reguły prywatności włączone. Każdy użytkownik widzi tylko swoje dane.
  • Error boundaries na frontendzie, globalny error handler na backendzie. Żaden błąd nie może cicho połknąć danych.
  • Rate limiting na wszystkich publicznych endpointach. Ochrona przed nadużyciem i DDoS.
  • Pipeline CI/CD z automatycznymi testami. Każdy push jest testowany przed wdrożeniem.
  • Monitoring i alerty (Sentry, CloudWatch). Wiesz o błędach zanim użytkownicy zaczną pisać.
  • Testy obciążeniowe z realistycznym ruchem. 100 równoczesnych użytkowników, nie jeden.
  • Środowisko staging odzwierciedlające produkcję. Testuj na kopii produkcji, nie na localhost.
  • Strategia migracji bazy danych. Planujesz zmiany schematu, nie robisz ich ad hoc.
  • Plan backupu i disaster recovery. Co się stanie, jak baza padnie? Masz odpowiedź?

Często zadawane pytania

Dlaczego wszystko działa idealnie na localhost?

Dlatego, że localhost to idealne środowisko: same-origin (brak CORS), zerowa latencja sieciowa, tryb developerski maskuje ostrzeżenia, Ty jesteś jedynym użytkownikiem (brak race conditions, brak obciążenia). Na produkcji każdy z tych warunków jest inny — i każdy może spowodować awarię.

Jaki jest najczęstszy powód awarii na produkcji?

Brakujące zmienne środowiskowe i hardcoded konfiguracja. To banalne, ale odpowiada za większość awarii «działa lokalnie, nie działa na produkcji». Twój .env ma klucze — serwer produkcyjny nie. AI hardcoduje URL-e w kodzie źródłowym zamiast używać zmiennych środowiskowych.

Skąd wiem, czy moja aplikacja jest gotowa na produkcję?

Proste pytanie: jeśli nie potrafisz odpowiedzieć «co się stanie, kiedy X padnie?» dla każdej krytycznej ścieżki, Twoja aplikacja nie jest gotowa. Co się stanie, kiedy baza danych będzie niedostępna? Co się stanie, kiedy API Stripe zwróci błąd? Co się stanie, kiedy 100 użytkowników kliknie «Kup» w tej samej sekundzie? Jeśli nie masz odpowiedzi — masz pracę do zrobienia.

Czy powinienem przepisać aplikację od zera?

Zazwyczaj nie. Najpierw zrób audyt. Zidentyfikuj krytyczne luki (bezpieczeństwo, baza danych, konfiguracja). Napraw je punkt po punkcie. Przepisanie od zera ma sens tylko wtedy, kiedy architektura jest fundamentalnie błędna — ale w większości przypadków można naprawić istniejący kod iteracyjnie, bez utraty dotychczasowej pracy.

Czy mogę wdrożyć na Vercel/Netlify i nazwać to produkcją?

Platforma nie równa się produkcji. Vercel i Netlify to świetne narzędzia do hostingu, ale sam hosting to nie jest «produkcja». Nadal potrzebujesz poprawnej konfiguracji CORS, monitoringu, obsługi błędów, bezpieczeństwa, właściwej bazy danych i testów obciążeniowych. Przycisk «Deploy» to początek, nie koniec.

Twoja aplikacja działa lokalnie, ale nie na produkcji?

Pomogę Ci zidentyfikować i naprawić każdy z tych problemów. Audyt, naprawa, wdrożenie — od prototypu do produkcji.

Zarezerwuj bezpłatną rozmowę →
Bezpłatna konsultacja Bez zobowiązań Odpowiedź w ciągu 24h