Budżety wydajności pomagają utrzymać aplikacje webowe szybkie przez ustalenie jasnych limitów czasu ładowania, rozmiaru JS i Core Web Vitals oraz przez szybkie audyty i zasady „najpierw napraw”.

Budżet wydajności to zestaw ustalonych limitów, na które zgadzacie się zanim coś zbudujecie. Może to być limit czasu (jak szybko strona się odczuwa), limit rozmiaru (ile kodu wysyłacie) lub prosty limit liczby (żądania, obrazy, skrypty stron trzecich). Jeśli przekroczycie limit, traktujecie to jak niedopełniony wymóg, a nie „fajnie naprawić później”.
Szybkość zwykle się pogarsza, bo wysyłanie jest addytywne. Każdy nowy widget dodaje JavaScript, CSS, fonty, obrazy, wywołania API i więcej pracy dla przeglądarki. Nawet małe zmiany sumują się, aż aplikacja zaczyna działać ciężko, szczególnie na telefonach średniej klasy i wolniejszych sieciach, gdzie jest większość realnych użytkowników.
Opinie tu nie chronią. Jedna osoba mówi „na moim laptopie jest ok”, inna „to wolne”, i zespół dyskutuje. Budżet kończy tę debatę, zamieniając wydajność w ograniczenie produktowe, które można mierzyć i egzekwować.
Tu wchodzi w grę myślenie Addy’ego Osmaniego: traktuj wydajność jak ograniczenia projektowe i zasady bezpieczeństwa. Nie „próbujesz” być bezpieczny ani „nie masz nadziei”, że layout będzie dobry. Ustalasz standardy, sprawdzasz je ciągle i blokujesz zmiany, które je łamią.
Budżety rozwiązują kilka praktycznych problemów naraz. Robią kompromisy jawne (dodanie funkcji oznacza zapłatę za nią gdzie indziej), wykrywają regresje wcześnie (gdy naprawy są tańsze) i dają wszystkim taką samą definicję „wystarczająco szybko”. Redukują też panikę, która pojawia się tuż przed wydaniem.
Oto scenariusz, do którego budżety są przeznaczone: dodajesz rozbudowaną bibliotekę wykresów dla jednego widoku dashboardu. Trafia do wszystkich, powiększa główny bundle i opóźnia pierwszy znaczący ekran. Bez budżetu przechodzi to, bo funkcja „działa”. Z budżetem zespół musi wybrać: lazy-load wykres, zastąpić bibliotekę lub uprościć widok.
To ma jeszcze większe znaczenie, gdy zespoły szybko generują i iterują aplikacje, także przy przepływach budowy sterowanych czatem jak Koder.ai. Szybkość jest świetna, ale ułatwia też wysyłanie dodatkowych zależności i ozdobników UI bez zauważenia. Budżety powstrzymują szybką iterację przed przemianą w wolne produkty.
Praca nad wydajnością zawodzi, gdy mierzysz wszystko i niczego nie masz na własność. Wybierz jedną ścieżkę strony, która ma znaczenie dla realnych użytkowników, i traktuj ją jak punkt odniesienia dla budżetów.
Dobry punkt startowy to podstawowa ścieżka, gdzie prędkość wpływa na konwersję lub codzienną pracę, np. „home → rejestracja”, „pierwsze ładowanie dashboardu po logowaniu” albo „checkout i potwierdzenie płatności”. Wybierz coś reprezentatywnego i częstego, nie krawędź scenariusza.
Twoja aplikacja nie działa na twoim laptopie. Budżet, który wygląda dobrze na szybmachine, może być wolny na telefonie średniej klasy.
Zdecyduj o jednej klasie urządzeń i jednym profilu sieci na start. Uprość i zapisz to zdaniem, które każdy może powtórzyć.
Na przykład: telefon z Androidem średniej klasy z ostatnich 2–3 lat, na 4G w ruchu (nie Wi‑Fi biurowe), mierząc cold load i potem jedną kluczową nawigację, w regionie, gdzie jest większość użytkowników.
To nie ma być wybór najgorszego przypadku. To wybór powszechnego przypadku, który faktycznie możesz optymalizować.
Liczby mają znaczenie tylko wtedy, gdy są porównywalne. Jeśli jeden test to „Chrome z rozszerzeniami na MacBooku”, a następny to „zwolniony mobile”, wykres trendu to hałas.
Wybierz jedno środowisko bazowe i trzymaj się go dla sprawdzeń budżetów: ta sama wersja przeglądarki, te same ustawienia throttlingu, ta sama ścieżka testowa i ten sam stan cache (cold albo warm). Jeśli używasz realnych urządzeń, używaj tego samego modelu.
Teraz zdefiniuj, co znaczy „wystarczająco szybko” w kategoriach zachowania, nie perfekcyjnych demonstracji. Na przykład: „użytkownicy mogą szybko zacząć czytać treść” albo „dashboard wydaje się responsywny po logowaniu”. Przetłumacz to na jedną lub dwie metryki dla tej ścieżki i ustaw budżety wokół nich.
Budżety działają najlepiej, gdy obejmują to, co użytkownicy odczuwają, i to, czym zespoły mogą sterować. Dobry zestaw łączy metryki doświadczenia (czy „wygląda szybko?”) z limitami zasobów i CPU („dlaczego stało się wolne?”).
Te śledzą, jak strona zachowuje się dla prawdziwych ludzi. Najbardziej przydatne mapują się bezpośrednio na Core Web Vitals:
Budżety czasowe są twoją gwiazdą północną, bo odzwierciedlają frustrację użytkownika. Nie zawsze jednak mówią, co naprawić, więc potrzebujesz też poniższych typów budżetów.
Te łatwiej egzekwować w procesie budowania i przeglądu, bo są konkretne.
Budżety wagowe ograniczają np. całkowity JavaScript, całkowity CSS, wagę obrazów i fontów. Budżety żądań ograniczają liczbę żądań i skryptów stron trzecich, redukując narzut sieciowy i „niespodziewaną” pracę od tagów, widgetów i trackerów. Budżety runtime limitują długie taski, czas na głównym wątku i czas hydracji (zwłaszcza dla React), co często tłumaczy, dlaczego strona „wydaje się” wolna na telefonach średniej klasy.
Praktyczny przykład z React: rozmiar bundla może wyglądać dobrze, ale nowy carousel dodaje ciężkie renderowanie po stronie klienta. Strona się ładuje, ale klikanie filtrów jest sztywne, bo hydracja blokuje główny wątek. Budżet runtime, np. „brak długich tasków powyżej X ms podczas startu” lub „hydracja kończy się w Y sekund na urządzeniu średniej klasy”, może to wykryć nawet gdy budżety wagowe nie reagują.
Najsilniejsze podejście traktuje to jako jeden system: budżety doświadczenia definiują sukces, a budżety rozmiaru, żądań i runtime utrzymują wydania uczciwe i ułatwiają odpowiedź na pytanie „co się zmieniło?”.
Jeśli ustawisz za wiele limitów, ludzie przestaną zwracać uwagę. Wybierz 3–5 budżetów, które najlepiej oddają to, co odczuwają użytkownicy, i które możesz zmierzyć przy każdym pull requescie lub wydaniu.
Praktyczny zestaw startowy (dostosuj liczby później):
Dwa progi utrzymują rozsądek. „Ostrzeżenie” mówi, że się odsuwasz. „Błąd” blokuje wydanie lub wymaga explicite zgody. To sprawia, że limit jest realny, bez tworzenia ciągłych alarmów.
Zapisz budżet w jednym wspólnym miejscu, żeby nikt o nim nie dyskutował podczas gorącego wydania. Zachowaj go krótko i konkretnie: które strony lub ścieżki obejmuje, gdzie uruchamiasz pomiary (lokalny audit, CI, staged build), jakie urządzenie i profil sieciowy używasz oraz dokładnie, jak definiujesz metryki (field vs lab, gzip vs raw, poziom trasy vs cała aplikacja).
Zacznij od powtarzalnego baseline'u. Wybierz jedną lub dwie kluczowe strony i testuj je na tym samym profilu urządzenia i sieci za każdym razem. Uruchom test co najmniej trzy razy i zapisz medianę, żeby jeden dziwny przebieg nie określił kierunku.
Użyj prostego arkusza bazowego, który zawiera zarówno metrykę użytkownika, jak i metrykę buildową. Na przykład: LCP i INP dla strony oraz całkowity rozmiar JavaScript i całkowite bajty obrazów dla builda. To sprawia, że budżety wydają się realne, bo widzisz, co faktycznie wyszło, a nie tylko to, co zgadł test labowy.
Ustaw budżety nieznacznie lepsze niż dziś, nie fantastyczne wartości. Dobra zasada to 5–10% poprawy od bieżącej mediany dla każdej ważnej metryki. Jeśli twoje LCP to 3.2s w baseline, nie skacz od razu do 2.0s. Zacznij od 3.0s, a potem zaostrzaj, gdy udowodnisz, że potrafisz go utrzymać.
Dodaj szybkie sprawdzenie do każdego wydania zanim trafi do użytkowników. Trzymaj je na tyle lekkie, by ludzie ich nie pomijali. Prosta wersja: uruchom audit jednej strony, z którą się umówiliście, zablokuj build jeśli JS lub obrazy przekraczają budżet, przechowuj wyniki per commit, żeby widzieć kiedy coś się zmieniło, i zawsze testuj ten sam wzorzec URL (bez losowych danych).
Przeglądaj naruszenia co tydzień, nie tylko gdy ktoś zacznie narzekać. Traktuj naruszenie jak błąd: zidentyfikuj zmianę, która je spowodowała, zdecyduj, co naprawić teraz, a co zaplanować. Zaostrzaj powoli, tylko gdy utrzymasz linię przez kilka wydań.
Gdy zakres produktu się zmienia, aktualizuj budżety świadomie. Jeśli dodasz nowe narzędzie analityczne lub ciężką funkcję, zapisz, co urosło (rozmiar, żądania, runtime), co zrobisz, by to „spłacić” później i kiedy budżet ma wrócić do normy.
Budżet pomaga tylko wtedy, gdy możesz go szybko sprawdzić. Celem 10‑minutowego audytu nie jest udowodnienie idealnej wartości. To wykrycie, co zmieniło się od ostatniego poprawnego builda i decyzja, co naprawić najpierw.
Zacznij od jednej strony reprezentującej rzeczywiste użycie. Potem uruchamiaj te same szybkie kontrole za każdym razem:
Dwa widoki zwykle dają odpowiedź w minutach: waterfall sieci oraz timeline głównego wątku.
W waterfall szukaj jednego żądania, które dominuje na ścieżce krytycznej: gigantyczny skrypt, blokująca czcionka lub obraz, który startuje późno. Jeśli zasób LCP nie jest żądany wcześnie, strona nie trafi w budżet LCP bez względu na szybkość serwera.
W timeline szukaj długich tasków (50 ms lub więcej). Klastrowanie długich tasków podczas startu często oznacza za dużo JavaScript na pierwsze ładowanie. Jeden masywny kawałek to zwykle problem z routingiem lub wspólnym bundlem, który urósł z czasem.
Szybkie audyty zawodzą, gdy każdy test jest inny. Zapisz kilka podstawowych rzeczy, żeby zmiany były czytelne: URL strony i wersja builda, urządzenie i profil sieci, opis elementu LCP, kluczowe liczby, które śledzisz (np. LCP, całkowite bajty JS, liczba żądań) oraz krótka uwaga o głównym winowajcy.
Testy desktopowe są ok dla szybkiej informacji zwrotnej i sprawdzeń PR. Użyj realnego urządzenia, gdy jesteś blisko budżetu, gdy strona wygląda szarpana lub gdy użytkownicy są głównie mobilni. CPU mobilne ujawniają długie taski najlepiej, i tam wiele „na moim laptopie jest ok” wydań się rozpada.
Gdy budżet zawodzi, najgorsze jest „optymalizuj wszystko”. Ustal powtarzalny porządek priorytetów, żeby każda poprawka miała jasny zwrot.
Zacznij od tego, co użytkownicy zauważają najbardziej, potem idź w kierunku drobniejszych poprawek:
Zespół wysyła nowy dashboard i nagle nie spełnia budżetu LCP. Zamiast grzebać w nagłówkach cache, znajdują, że element LCP to pełnoekranowy obraz wykresu. Zmniejszają jego rozmiar, serwują lżejszy format i ładują tylko to, co ważne na początku. Potem zauważają, że duża biblioteka do wykresów ładuje się na każdej trasie. Ładują ją tylko na stronie analitycznej i opóźniają widget wsparcia stron trzecich aż po pierwszej interakcji. W ciągu dnia dashboard wraca w budżet, a kolejne wydanie ma jasne odpowiedzi „co się zmieniło”.
Największy tryb awarii to traktowanie budżetów jak jednorazowego dokumentu. Działają tylko wtedy, gdy są łatwe do sprawdzenia, trudno je ignorować i są powiązane z tym, jak wysyłacie.
Większość zespołów wpada w kilka pułapek:
Częsty scenariusz to „mała” funkcja, która ściąga nową bibliotekę. Bundle rośnie, LCP spowalnia o sekundę na wolniejszych sieciach i nikt nie zauważa, aż przychodzą zgłoszenia do wsparcia. Budżety istnieją, by uczynić tę zmianę widoczną podczas review.
Zacznij od prostoty i trzymaj sprawdzenia spójnymi. Wybierz 2–4 budżety, które mapują doświadczenie użytkownika i zaostrzaj je stopniowo. Zablokuj ustawienia testu i zapisz je. Śledź przynajmniej jeden sygnał od realnych użytkowników, jeśli możesz, i używaj testów labowych do wyjaśniania „dlaczego”, nie do wygrywania kłótni. Gdy zależność dodaje znaczącą wagę, wymagaj krótkiej notatki: ile kosztuje, co zastępuje i dlaczego jest tego warta. Najważniejsze: umieść sprawdzenie budżetu na normalnej ścieżce wydania.
Jeśli budżety wydają się ciągłym tarciem, zwykle są nierealistyczne na dziś lub nie są powiązane z rzeczywistymi decyzjami. Napraw te dwie rzeczy najpierw.
Mały zespół zbudował dashboard analityczny w React w tydzień. Na początku wydawało się szybko, ale każde piątkowe wydanie dodawało trochę wagi. Po miesiącu użytkownicy zaczęli mówić, że pierwszy ekran „zawiesza się” i filtry działają wolno.
Przestali się kłócić o „wystarczająco szybko” i zapisali budżety powiązane z tym, co użytkownicy zauważają:
Pierwsze naruszenie ujawniło dwa problemy. Początkowy bundle JS urósł, gdy dodano wykresy, biblioteki dat i zestaw UI. Jednocześnie nagłówek dashboardu został zamieniony na większy plik „tymczasowo”, co przesunęło LCP poza limit. INP pogorszyło się, bo każda zmiana filtra wywoływała ciężkie rerendery i kosztowne obliczenia na głównym wątku.
Naprawili to w kolejności, która dała szybkie efekty i zapobiegła ponownym regresjom:
Przywrócenie LCP poniżej progu przez zmniejszenie i skompresowanie obrazów, ustawienie jawnych wymiarów obrazów i unikanie blokujących fontów.
Redukcja początkowego JS przez usunięcie nieużywanych bibliotek, podział tras i lazy-load wykresów.
Poprawa INP przez memoizację kosztownych komponentów, odfiltrowanie wpisywania (debounce) w filtrach i przeniesienie ciężkiej pracy poza ścieżkę krytyczną.
Dodanie sprawdzenia budżetu do każdego wydania, by gdy metryka się złamie, wydanie czekało.
Po dwóch wydaniach LCP spadło z 3.4s do 2.3s, a INP poprawiło się z ok. 350ms do poniżej 180ms na tym samym urządzeniu testowym.
Budżet pomaga tylko wtedy, gdy ludzie go konsekwentnie stosują. Trzymaj go małym, zapisz i włącz do procesu wysyłania.
Wybierz garść metryk dopasowanych do aplikacji, ustaw progi „ostrzeżenie vs błąd” i udokumentuj dokładnie, jak testujesz (urządzenie, przeglądarka, sieć, strona/przepływ). Zapisz raport bazowy z najlepszego aktualnego wydania i oznacz go wyraźnie. Zdecyduj, co jest dopuszczalnym wyjątkiem, a co nie.
Przed każdym wydaniem uruchom ten sam audyt i porównaj z baseline. Jeśli coś się cofa, zarejestruj to tam, gdzie śledzisz błędy i traktuj jak niedziałający krok checkout, nie „na później”. Jeśli wysyłasz z wyjątkiem, zapisz właściciela i datę wygaśnięcia (zwykle 1–2 sprinty). Jeśli wyjątek ciągle jest odnawiany, budżet wymaga poważnej dyskusji.
Przenieś budżety wcześniej na etapie planowania i estymacji: „Ten ekran dodaje bibliotekę wykresów, więc musimy coś usunąć albo lazy-loadować”. Jeśli budujesz z Koder.ai (koder.ai), możesz też zapisać te ograniczenia z wyprzedzeniem w Planning Mode, potem iterować w mniejszych kawałkach i używać snapshotów oraz rollbacku, gdy zmiana przekroczy limit. Chodzi nie o narzędzie, a o nawyk: każda nowa funkcja musi zapłacić za swoją wagę, albo nie wypuszcza się jej.
A performance budget is a set of hard limits (time, size, requests, CPU work) that your team agrees to before building.
If a change exceeds the limit, treat it like a broken requirement: fix it, reduce scope, or explicitly approve an exception with an owner and an expiry date.
Because performance gets worse gradually. Each feature adds JavaScript, CSS, images, fonts, API calls, and third‑party tags.
Budgets stop the slow creep by forcing a tradeoff: if you add weight or work, you must pay it back (lazy-load, split a route, simplify UI, remove a dependency).
Pick one real user journey and one consistent test setup.
A good starter is something frequent and business-critical, like:
Avoid edge cases at first; you want a flow you can measure every release.
Start with one target that matches typical users, for example:
Write it down and keep it stable. If you change device, network, cache state, or the path you test, your trend becomes noise.
Use a small set that covers both what users feel and what teams can control:
A practical starter set is:
Use two thresholds:
This avoids constant fire drills while still making the limits real when you cross the line.
Do this in order:
Not always. Bundle size can be fine while the page still feels slow because the main thread is busy.
Common React causes:
Add a runtime budget (for example, limit long tasks during startup or set a hydration time cap) to catch this class of issues.
Fast generation and iteration can quietly add dependencies, UI flourishes, and third-party scripts that ship to everyone.
The fix is to make budgets part of the workflow:
This keeps fast iteration from turning into a slow product.
Timing metrics show the pain; size and runtime limits help you quickly find what caused it.
Pick 3–5 budgets first. Tune later based on your baseline and release history.
Treat the breach like a bug: identify the commit, fix or scope-reduce, and prevent repeats.