Skip to content
⚡ LIVE From Lizard to Wizard · Wednesday, August 5 · LIMITED SEATS Save my seat →
Episode 33 55 minutes

Frontend Foundations at Scale with Giorgio Polvara

Key Takeaways from our conversation with Giorgio Polvara

Giorgio Polvara

Staff Engineer at Perk (formerly TravelPerk), Frontend Foundations Builder

Señors @ Scale host Neciu Dan sits down with Giorgio Polvara, Staff Engineer at Perk (formerly TravelPerk), who joined when the company was 15 people in two flats with a hole knocked through the wall and helped build the frontend foundations that still hold up at unicorn scale. Giorgio covers the multi-year migration from a monolithic frontend to vertical micro-frontends, why their first attempt with single-spa didn't work, how they pulled off a full rebrand behind feature flags without leaking, and the staff engineer mindset of treating every feature as a system improvement.

🎧 New Señors @ Scale Episode

This week, I spoke with Giorgio Polvara, Staff Engineer at Perk (formerly TravelPerk). Giorgio has been writing code for nearly 20 years — starting with PowerPoint quizzes at 12, Turbo Pascal at 14, and a summer of jQuery and Adobe Flex working at his father's software studio in Italy. He joined TravelPerk when it was 15 people in two flats in Raval with a hole punched between them, and helped build the frontend foundations that now serve a unicorn with 1,800 employees globally.

In this episode, we go deep on the multi-year migration from a monolithic frontend to vertical micro-frontends, why their first attempt with single-spa didn't fit, how they pulled off a full company rebrand behind feature flags without leaking the design, and what the staff engineer role actually looks like across tribes.

⚙️ Main Takeaways

1. From PowerPoint quizzes to Staff Engineer at a unicorn

Giorgio's path into engineering started with a teacher showing him you could put buttons in PowerPoint slides.

  • The spark: At 12, his teacher showed the class that buttons in PowerPoint could jump to different slides. He started building four-button quizzes — one wrong answer slide, three right ones — and decided then he wanted to work with computers.
  • The first real code: Turbo Pascal at 14. Two variables, sum them, print "The sum is 10." He copied the code, hit compile and run, and was hooked.
  • The jQuery moment: At 16, someone showed him jQuery — click a button and a whole div disappears in one line of code. "That was an initiation for many." Debugging meant alert() calls because there was no inspector yet.
  • The Flex side gig: At his father's 8-10 person software studio, his job was studying things nobody else had time to study. One client wanted bubble sounds on button hover before the audio tag existed — Giorgio built it with embedded Adobe Flex.

2. Joining TravelPerk at 15 people through a Slack channel

The job that built the foundations was found on a local JavaScript meetup Slack.

  • The find: After moving to Barcelona for a conference, Giorgio looked for work in the Barcelona JS Slack channel. TravelPerk had a posting.
  • The office: Two flats in Raval with a hole knocked through one wall to connect them. 15 people total.
  • The growth: "Every day there is something new. Every day there are some changes." From standing standups to two-team standups to multiple offices to a tribe structure. The constant: nothing stays the same long enough to get used to it.
  • The takeaway: Once you're in hyper-growth, you stop noticing it. You only see the seams when you look back.

3. Code quality during hyper-growth: alternate, don't allocate

Giorgio doesn't believe in the "20% time for refactoring" model.

  • The reality: Different departments pull in different directions. Product wants new features. Engineering wants to fix the code. Finance wants to spend less. That tension is normal — leadership decides which way to lean each cycle.
  • The pattern: Tight deadline incoming → take on technical debt deliberately → ship the feature → validate in production → come back and fix the corners cut. Alternate periods of high feature velocity with periods of cleanup.
  • The mindset shift: "I'm a strong believer in the idea that you are not creating a feature — you're improving your system, and the by-product is also a new feature." Reframe every ticket as system improvement first, feature second.

4. Why the first micro-frontend attempt with single-spa failed

The horizontal split looked clean on paper but produced messy boundaries in production.

  • The problem they were solving: The frontend was becoming impossible to work in. Local dev server compiles long enough to "go get a coffee." A single broken test in CI blocked everyone's deploys. Teams kept stepping on the same files because there was no clear boundary separation.
  • The first attempt: single-spa — a router running in the browser deciding which micro-frontends to mount/unmount based on path. A horizontal client-side merge.
  • The failure mode: No real boundary separation. One CSS bug had a micro-frontend unmounting and accidentally stripping all the styles on the page when navigating away. Complexity was still very high.
  • The other constraints: single-spa was webpack-only at a time when they wanted to experiment with Vite. Roadmap features they needed had unclear timelines, and they didn't have the capacity to fork.

5. The vertical split that actually worked

Each micro-frontend became its own single-page application.

  • The architecture: A server-level JavaScript function looks at the path and routes to the appropriate micro-frontend. Visit /flights, get the flights micro-frontend served as its own SPA.
  • The mental model: "If you work in the flight squad, you can just pretend you are building an application to search flights. That's it. The rest of the world doesn't exist." No worrying about authentication or payment — just redirect to another page.
  • The trade-off: A full page refresh when crossing micro-frontend boundaries. Acceptable because users complete a flow inside one micro-frontend before jumping to another.
  • The result: Squads that estimated tickets at four days started shipping them in one. They stopped getting blocked by other teams.
  • The next step: Investigating service workers for asset pre-caching, API call caching, and the View Transitions API to make jumps imperceptible.

6. How the monorepo enforces a single stack across micro-frontends

Freedom to experiment, but with clear gravity toward the standard.

  • The setup: All micro-frontends live in one monorepo with pnpm + syncpack. Install a different version than the rest of the system and it yells at you. Exceptions are possible but not the default.
  • The Vite plugin: The Vite config for every micro-frontend is one line that calls a shared plugin. Want to change how assets are handled platform-wide? Modify the plugin once and every micro-frontend gets it.
  • The social contract: Teams can experiment with different stacks (one tried Next.js), but the Foundation Tribe doesn't support unsupported choices. Some experiments get adopted as the official stack — they just migrated from Jest to Vitest because it's faster with a similar API. Some get abandoned (Next.js).
  • The acquisition wrinkle: When they acquired a company with an Angular app, they embedded it as a micro-frontend — their architecture treats anything that emits HTML as valid. Shared components like navigation got rewritten as Web Components to bridge React and Angular until they finished rewriting the acquired app in React.

7. Tribes, squads, and how Perk adapted the Spotify model

Cross-functional teams owned by business domain, not by technology.

  • The structure: Tribes started from the Spotify model and got adapted. Tribes are organized by business domain — onboarding, booking, platform. Inside each tribe, multiple squads (e.g., flights, hotels) own their domain end-to-end.
  • The composition: Each squad has backend, frontend, full-stack, a dedicated designer, and a PM. They discuss with leadership, get quarterly approval, and ship without back-and-forth resource requests.
  • The naming: "I find it weird that every company names this thing differently. Some call it tribes, some clusters, some communities."

8. Pulling off a full rebrand behind feature flags without leaking

Last year Perk changed name, domain, logo, font, spacing, and color system — all live in production behind flags.

  • The constraint: The new design could not leak ahead of the marketing announcement. So the team built the new version using fake colors and fake logos until the very last moment.
  • The hard part: The design system existed but wasn't used everywhere — large parts of the app pre-dated it. They went page by page checking what broke.
  • The implementation: A hook decided whether to apply old or new styles. For small things (different margins) — if (hook) { newMargin } else { oldMargin }. For components that looked completely different, a shell component picked between an old version and a new version.
  • The cleanup: Once the flag was switched, finding all usages of the deprecated hook plus TypeScript flagging "this condition is always true" made cleanup straightforward.
  • The cultural piece: They ditched the regular sprint cycle for a few months. Created a task force. Opened the new rebrand to every Perk employee internally — anyone could flag bugs in Slack or Forma. "This idea of 'if you see something, say something' caught so many bugs because everyone in the company was looking at it."
  • The outcome: Big change, smooth release. A couple of misaligned pages, fixed quickly. "I was surprised. Usually you have a lot of issues with this kind of stuff."

9. CSS migration: from styled-components to CSS Modules with CSS Variables

The migration piggybacked on the rebrand work.

  • The why: styled-components is in maintenance mode. No advantage in staying.
  • The migration target: CSS Modules across the design system and a big chunk of the application.
  • The bonus: Used the migration to introduce CSS Variables. Design tokens that lived as JavaScript values became actual CSS variables, unlocking dynamic theming and runtime updates.

10. CI that scales with micro-frontends and a shared design system

The CI pipeline figures out what changed and runs only what's needed.

  • The setup: The Foundation tribe owns one CI pipeline used by every team.
  • The first step: Detect changed files. Modified one micro-frontend? Run only its tests. Modified the design system package? Run its tests plus tests for every micro-frontend that uses it.
  • The automatic version policy: Micro-frontends always use the latest version of internal packages automatically. Update the design system, and everything redeploys.
  • The mindset: "It sounds a bit scary. But if you start doing it a lot and you add monitoring, it just becomes second nature."

11. Schema validation in production with Zod

Early-stage experiment to catch API drift without breaking users.

  • The current model: Define the response type in TypeScript. That's it. No runtime check.
  • The Zod experiment: Define the response shape in Zod. Validate the actual response asynchronously after rendering. If it doesn't match, alert the on-call engineer.
  • The reasoning for async: "We don't want a customer to get a blank page because we did something wrong." Most schema drift is harmless — number arrives as a stringified number, code keeps working. Just want to know about it.
  • The composability: From the Zod schema you derive the TypeScript types. They also have a library called Fabricator that generates test data — soon, that data will come from the same Zod schema. Schema as source of truth.
  • vs PACT contract testing: Not a replacement. PACT validates workflow sequences ("user does X, API returns Y"). Zod validates response shape. Different layers, both useful. "When you do tests and quality assurance, you want different layers. The more layers you have, the less bugs go through."

12. Becoming a manager taught him he wanted to stay an engineer

A year as Engineering Manager at Toptal clarified his career direction.

  • The Toptal stint: Hired explicitly as Engineering Manager after doing some EM work as a side responsibility at TravelPerk. Wanted to take it on as a career.
  • The imposter syndrome: Wanted to do a good job, didn't know if he could. Eventually relaxed, got good feedback from his reports, and learned why managers ask for estimates (because the quarter has to be planned).
  • The realization: "I don't like this thing of having to evaluate a person every quarter and talk about promotion. It's a kind of pressure I don't enjoy." A year away from coding made him realize how much he missed it.
  • The frustration we shared: Being a manager and having no real power to promote someone — even when reviews said they exceeded expectations, leadership took the decision. "I felt I was just passing messages from one layer to another."
  • The return: He came back to TravelPerk as a Staff Engineer, where he could do architecture across tribes without being responsible for performance reviews.

13. The Staff Engineer role: impact and autonomy across tribes

The definition Giorgio uses at Perk.

  • Impact widens with seniority: Junior engineers know their squad's scope. Seniors understand their tribe's concerns. Staff engineers work across tribes — like leading the multi-year monolith-to-micro-frontends migration that affected every developer in the company.
  • Autonomy is the other axis: Juniors should ask questions all the time. "If you're a junior, don't be afraid of asking questions. It's exactly what I'm expecting of you." Staff engineers are the ones answering — they get a problem, analyze it, propose a solution on their own.
  • The career advice: To go from senior to staff, find problems outside your squad and tribe. Identify them, analyze them, propose solutions. "I would propose five different proposals and if I'm lucky one is picked up." Then implement, measure, iterate.
  • The non-technical skill: How you present the proposal matters. Engineers want libraries, CI, technical detail. Stakeholders want money, revenue, time saved. "That becomes increasingly important as you progress in your career — convincing people that your idea makes sense."

🧠 What I Learned

  • TravelPerk's frontend foundations were built when the office was two Raval flats connected by a hole in the wall and the team was 15 people.
  • During hyper-growth, alternate phases of feature debt with phases of cleanup. Don't allocate a fixed 20% for refactoring — treat every feature as system improvement first.
  • The first micro-frontend attempt at Perk used single-spa with a horizontal client-side split. It failed because boundaries weren't actually separated and complexity stayed high.
  • The vertical split — each micro-frontend as its own SPA, server-side path routing — works because each squad can pretend the rest of the platform doesn't exist.
  • Squads that estimated tickets at four days started finishing them in one after the migration.
  • A monorepo with pnpm + syncpack enforces a single stack while still allowing experimentation.
  • Vite config as a shared plugin lets you change platform-wide build behavior in one place.
  • Acquiring a company with an Angular app? Embed it as a micro-frontend and bridge shared components with Web Components.
  • A company-wide rebrand can ship behind feature flags without leaking — use fake colors during dev, switch them at the last moment, open the flagged version internally so everyone hunts bugs.
  • styled-components is in maintenance mode. Migrate to CSS Modules and use the opportunity to introduce CSS Variables.
  • CI should detect what changed and run only what's needed. Internal packages should auto-bump to latest.
  • Zod async response validation in production catches API drift without breaking users on schema mismatches.
  • PACT and Zod schemas validate different things. Use both — defense in layers.
  • A year as Engineering Manager taught Giorgio he prefers being a Staff Engineer working across tribes to evaluating reports each quarter.
  • Staff Engineer = impact across tribes + autonomy. The path: find problems outside your squad, propose solutions, present them in the language of the audience.

💬 Favorite Quotes

"Every day there is something new. Every day there are some changes. You start with we're all literally in the same room having a stand-up standing — to splitting two teams because the stand-up is just taking an hour."

"You are not creating a feature — you're improving your system, and the by-product is also a new feature. If you apply this mindset, it becomes much easier to maintain the system because it's your primary goal."

"If you work in the flight squad, you can just pretend that you are building an application to search flights. That's it. The rest of the world doesn't exist."

"It sounds a bit scary. But if you start doing it a lot and you add monitoring, it just becomes second nature."

"When you do tests and quality assurance, you want different layers. You don't want to have one thing that tests the thing. The more layers you have, the less bugs go through."

"If you're a junior, don't be afraid of asking questions. It's exactly what I'm expecting of you."

🎯 Also in this Episode

  • Bubble sounds on button hover for an Italian restaurant website — built with Adobe Flex before the audio tag existed
  • The Google Photos clone he built with a colleague in early 2000s, sending JavaScript values to the PHP backend session because he couldn't find them in the frontend
  • The Angular 2 rewrite era that pushed many companies (including TravelPerk) toward React around 2016
  • Going from full-stack at a Ruby on Rails + Angular fintech to specialized frontend because nobody else liked frontend
  • Why a hook is better than duplicate components for feature-flagged migrations — TypeScript helps clean up after deprecation
  • Internal Slack and Forma channels for company-wide bug reporting during the rebrand
  • Backend stack at Perk: Python + Django, with a growing amount of Lambda functions
  • Their internal design library "suitcase" used across all micro-frontends
  • Why they don't auto-generate React Query hooks from OpenAPI specs (yet)
  • The Fabricator library for generating test data — and the plan to drive it from Zod schemas
  • Why architecture must stay malleable: "Last two years we changed the name, the domain, the logo, everything. You just have to expect that things are going to change."

Resources

More from Giorgio:

  • Perk — formerly TravelPerk, the business travel unicorn
  • single-spa — the micro-frontend router they tried first
  • Vite — the build tool they migrated to from webpack
  • Vitest — their test runner, migrated from Jest
  • Zod — runtime schema validation library
  • PACT — contract testing framework
  • pnpm + syncpack — monorepo package management

Books mentioned:

🎧 Listen Now

🎧 Spotify
📺 YouTube
🍏 Apple Podcasts

Episode Length: 55 minutes on micro-frontends, monorepo architecture, surviving a rebrand behind feature flags, and the staff engineer mindset of treating every feature as a system improvement.

If you're scaling a frontend past the point where everyone can stand in one room, considering a monolith-to-micro-frontend migration, or trying to figure out what the staff engineer role actually means in practice, this conversation is for you.

Happy building,
Dan

🏆 SOLD OUT IN SINGAPORE · ATHENS · LONDON

From Lizard to Wizard

4-hour remote system design intensive.
Chat apps, microfrontends, BFF, SDUI, event-driven, observability.

€299 4-HOUR INTENSIVE
Save your seat →

Spots are vanishing. Don't be the one who waited.

💡 More Recent Takeaways

Monorepos at Scale with Santosh Yadav
Episode 40

Señors @ Scale host Neciu Dan sits down with Santosh Yadav, principal developer advocate at CodeRabbit and one of only around 80 GitHub Stars in the world. Santosh started hating C in 2004, fell for C# by 2008, and turned a year of open source contributions to Angular and NgRx into a stack of community titles — Google Developer Expert, GitHub Star, Nx champion, and Microsoft MVP. As a staff engineer at Celonis he led the move of 20-plus apps to module federation and drove Nx adoption across 30-plus teams when the product grew from four apps to thirty. From the year-long incremental migration off a single deployable unit, to why polyrepos can't give AI tools the context they need, to how Nx's affected graph and build caching tame a 20-million-line monorepo, to running code review for free for open source at CodeRabbit, this is the monorepo conversation grounded in someone who actually shipped one at scale.

Routing at Scale with Nicolas Beaussart-Hatchuel
Episode 39

Señors @ Scale host Dan Neciu sits down with Nicolas Beaussart-Hatchuel, staff engineer at Payfit and one of the maintainers of TanStack Router. Nicolas's path started with C macros to auto-generate his student paper headers and frontend learned by building phishing login pages for practice, took him through an iframe-based AngularJS-to-Angular 2 micro frontend migration at a web radio platform, into open source contributions across NX, ESLint, Vite and Hasura, and finally to maintaining one of the most ambitious routers in the React ecosystem. From why TanStack Router exists, to migrating Payfit's 300-route, 1.5-million-line codebase off React Router v5 using the strangler pattern, to collapsing 25 polyrepos and five different micro frontend strategies into a single modular monolith, this is the routing conversation most engineers never get.

Redux at Scale with Mark Erikson
Episode 38

Señors @ Scale host Neciu Dan sits down with Mark Erikson, maintainer of Redux and senior front-end engineer at Replay.io, where he works on a time-traveling debugger. Mark's path started with a 286 he got at eight years old, ran through a computer science degree, four years teaching English in China, embedded software at Northrop Grumman emulating legacy CPUs in old aircraft, and a chain of projects — GWT, jQuery, Backbone — that led him to React and Redux. From the @deprecated backlash that had people insulting him on the internet, to why the Redux core hasn't meaningfully changed since 2016, to what RTK Query actually solves, the underused listener middleware, building source maps into React's own build pipeline, and how Replay's recordings now hand debugging over to AI agents — this is the Redux conversation grounded in two decades of shipping software.

TanStack Query at Scale with Dominik Dorfmeister
Episode 37

Señors @ Scale host Dan Neciu sits down with Dominik Dorfmeister — better known as TkDodo — the maintainer of TanStack Query and a software engineer at Sentry. Dominik's path started at a technical high school in Vienna, ran through JVM backend work in Java and Scala, and turned to frontend around the introduction of TypeScript. During the pandemic lockdowns in Austria he started answering questions in the TanStack Discord, got addicted to the instant gratification of helping people, and slowly turned that into a blog, a first code contribution six to eight months later, and eventually maintainership of TanStack Query. From tracked queries and the chaotic version-three-to-four rename, to the version-five mistake he still dreads, to ripping 28,000 lines of dead code out of Sentry with Knip and building Sentry's new design system, this is the open source maintenance conversation most developers never get to hear.

📻 Never Miss New Takeaways

Get notified when new episodes drop. Join our community of senior developers learning from real scaling stories.

💬 Share These Takeaways

Share:

Want More Insights Like This?

Subscribe to Señors @ Scale and never miss conversations with senior engineers sharing their scaling stories.