More from Miguel Carranza
I recently wrote an internal Management 101 guide for new RevenueCat managers. It is not meant to be a universal management guide. Most universal management advice is either too vague to be useful or too generic to survive contact with a real company. My goal was simpler: explain what we expect from managers, why the role matters, what tends to feel weird at first, and where to start when things get messy. One of the sections I think matters most is the dopamine problem, because it is one of the most immediate changes. The weirdest part of becoming a manager is that your old scoreboard disappears. As an IC, you can point to things you shipped. Code merged. Bugs fixed. Systems improved. Customers helped. Even hard weeks usually have visible artifacts. Management work is slower and less satisfying in the short term. You can have a great week and nothing obvious happened. A project got slightly clearer. A candidate stayed warm. A conflict did not become a fire. A direct report heard feedback early enough to fix something. A team avoided a bad architectural decision. A future manager took one more step toward readiness. That is real work. It just does not always feel like it. This is one of the hardest parts of the transition from IC to manager, especially for Engineering Managers. You are used to being useful in a very concrete way. You know how to debug the issue, review the design, write the code, fix the incident, and unblock the team. Then suddenly a lot of your work becomes indirect. You need to stop trying to solve the problem in front of you. You need to make the team better at solving that type of problem in the future. It is also getting harder in the age of AI. Agentic coding is even more addictive. You can describe what you want, watch the agent work, review the diff, and get a working prototype or bug fix in minutes. The loop is fast and incredibly satisfying. This is why many new managers cling to coding, technical details, or direct execution. It gives them the old dopamine. It also feels useful when there is urgency: a project is at risk, a technical issue is blocking the team, or execution is moving slower than you think it should. Sometimes stepping in directly is the right call. If production is broken, do not sit there having a philosophical debate about leverage. Help. But most of the time, direct execution is a patch around the real problem. If the project only moves when you personally drive it, something else is broken. Maybe ownership is unclear. Maybe the team does not have enough context. Maybe the technical plan is too complex. Maybe the bar is too low. Maybe someone needs feedback. Maybe you have the wrong people on the problem. Maybe you are still acting like the tech lead because that is more comfortable than acting like the manager. Your job is to make the team capable of executing without you, either by hiring the right people, training people up, clarifying ownership, or raising the bar. If you keep solving the work yourself, you prevent yourself from learning the new job and prevent the team from growing into it. You need to rewire your satisfaction from “I shipped the thing” to “the team is stronger and shipping better because of the work I did.” That takes time. Some practical advice: Set weekly goals for yourself. Not vague goals like “be a good manager.” Concrete goals: write the 30/60/90 plan, give feedback to X, unblock Y, clarify ownership for Z, source X candidates, review hiring funnel metrics, talk to another manager about a problem. Create accountability. I use weekly emails. Use whatever works, but do not let weeks disappear into meetings. A full calendar is not evidence of impact. Write things down. Writing forces clarity and creates artifacts when the work itself is abstract. If you cannot write the decision clearly, you probably have not made the decision. If you cannot write the feedback clearly, you probably do not understand the behavior well enough yet. Look for compounding work. Better onboarding, better interview calibration, clearer team ownership, stronger tech leads, training people up, and improved decision-making pay off repeatedly. They may not feel as satisfying today, but they make the company more capable. Management is not a promotion from building. It is a different way of building. You are building the system around the work: the team, the standards, the ownership model, the feedback loops, the hiring bar, the culture, the decision-making. The hard part is that the system does not always give you a green checkmark at the end of the day. Do it anyway. Originally published as an X article on July 10, 2026 and archived here.
RevenueCat now has more than 150 team members. Around 100 of them are in my org. This is still a little crazy to me. My own org is now bigger than any company I had worked at before starting RevenueCat. As a technical founder, I always preferred computers over people. Computers are deterministic. People are emotional. But if you find real PMF, team building becomes unavoidable. You have to build more. You have to move faster. You have to do more things in parallel. And at some point, the company stops being a product that a small group of people can brute force into existence and becomes an organization that needs to keep improving without breaking itself every week. I have made a lot of mistakes over the last almost 9 years. Some were obvious in hindsight. Some were expensive. A few were probably unavoidable. These are 100 of the lessons I have learned getting to a 100-person org. Recruiting is a long game. Just because someone says no today does not mean it is a no forever. Build the relationship, leave a good impression, and keep the door open. Hiring is always a priority, even when you are ahead of the headcount plan. If the company is growing, it is much easier to fall behind than to stay ahead. External recruiting agencies rarely work. Their incentive is not to find the best fit; it is to close a candidate as fast as possible. Excellent recruiters are very hard to find. When you do find one, everyone’s life gets a lot easier. The brand compounds like every other company metric. Candidates who were unreachable a year ago may eventually reply. Great people attract more great people. Hire enough of them and recruiting starts to get its own kind of virality. Most people oversell when recruiting. Don’t. The best candidates see through the BS and value honesty about both the good and the bad. Candidates appreciate knowing the salary and process upfront. It saves time for both sides. Have a compensation philosophy you can explain and defend. People might take a pay cut, but nobody wants an unfair offer. Focus on candidate experience. Some people will inevitably get upset, but keep improving the process. Magic happens when candidates have a great experience even after being rejected: they re-apply later and even refer friends. Technical interviews are already stressful. Do not make them more stressful than necessary. Avoid obscure questions, make the interview close to the real job, and encourage collaboration. If your interview process works, do not bend it under pressure. Consistency and fairness come from sticking to a standard loop. Spend time looking at recruiting metrics: pass rates, interviewer variance, stage conversion, and close rates. They will help you debug calibration problems. At a certain scale, when multiple people run the same interview, assign a DRI to calibrate interviewers and review scorecards. Watch out for interviewers who always grade YES, but never STRONG YES or STRONG NO. Read between the lines. They are probably uncalibrated. A candidate with several STRONG YESes and one NO is often more interesting than someone with YESes across the board. Keep an eye on how many interviews your best ICs are doing. It can become distracting and hurt shipping velocity. Constantly train new interviewers through reverse shadowing. Being desperate for a hire usually turns into lowering the bar. Avoid the temptation. The flags you see during the interview process almost always show up 10x at work. Pedigree is a weak substitute for evidence. We all make mistakes when we see shiny resumes, but there are bad people at great companies too. Watch out for people who have seen scale, but have not done the scaling. They are easy to spot if you ask detailed questions about the problems they faced and how they solved them. Watch out for repeated short stints. Everyone can get unlucky once or make a bad judgment call. Multiple times is a pattern. Never skip reference calls. Even with a strong referral, do at least two. I have yet to see a candidate with weak references work out well. Backchannel references matter even more for executives. You will learn more there than in the interview process. If the references are not stellar, it is probably not worth the risk. Everyone wants feedback when they are rejected, but be careful with what you share. The reason is usually technical ability, culture fit, or both. A lot of people do not want to hear it. If they meet the bar, hiring users can be a great hack. They already know the product, including the good and the bad parts, so onboarding is much faster. Attitude and values alignment matter more than raw technical skill. If the foundations are there and the team is strong, the candidate can grow. A genius who is not aligned with the team is a recipe for disaster. Always hire pragmatic engineers. Avoid dogmatic ones. We only get to play with computers because we serve customers. Migrating to the trendiest architecture with zero customer impact is a red flag. Never hire an engineering leader you cannot have a nerdy conversation with. They need to be deeply technical. Do not settle for a therapist or coach. Everyone wants to work from home, but only a minority of people are disciplined and self-motivated enough to work remotely. Hire for flexibility, but be flexible too. Understand what motivates people. If they are doing great work and are excited about a different internal role, make room when the fit is real. You will mislevel candidates. It is okay. Under-leveling is easier to fix than over-leveling. Correct it as soon as it is obvious, and treat it as fixing a hiring mistake, not as a normal promotion. For every manager you hire, prepare a serious onboarding document: the team, their backgrounds, past reviews, strengths, current problems, and open questions. Then have them write a 30/60/90 plan. The easiest way to know if a new leader is working is to agree upfront on the success case and failure case in the 30/60/90 plan. The more objective it is, the clearer the decision becomes. Hiring mistakes do not mean the person sucks. They mean the person is not a fit for the current team. Not acting quickly is unfair to customers and coworkers. Do a postmortem after every separation, voluntary or involuntary. There is almost always something to learn. Do not be stingy with severance. You made the hiring mistake. Ultimately, that is on you. Most executives are full of shit. Many are career-driven status seekers who know how to sell themselves. The job is to find the actual builders, and they are rare. A great exec will make the company feel brand new. A mediocre one can destroy your culture, and if you are not careful, your company. Spend time with executive candidates in person. Watch how they think, work, and interact when they cannot perform a polished interview answer. Management sucks. Be suspicious of people who want to become managers. The best ones usually never wanted to be managers in the first place, but had to do the job and got good at it. The manager is not expected to do the IC job, but they better be able to do the job and be damn good. Management is not only managing ICs. It is also managing up. The best managers make fewer surprises happen. If you have a good team, managers should spend most of their time on delivery and some of their time on people. Sound the alarm if those percentages flip. Even the best managers need calibration, not just trust. Spend the time with them until they are calibrated. Only then do you get real leverage. Try to keep a healthy ratio between internal and external managers. Internal managers bring institutional knowledge. External managers bring management reps. Both sides need what the other has. Tricking people into management by starting them in technical leadership roles has been a useful way for us to scale, especially with established teams. But the transition from technical leader to actual manager needs to be very intentional. Hiring, org design, and long-term planning do not come naturally to most technical leaders. Middle managers initially have almost no incentive to terminate anyone. It creates conflict and feels optional. Support them through it. Once they see the team is better off without a bad fit, they start to understand. When managing managers, do not let them hire someone you would not want to manage yourself. Never promote someone out of fear or for retention. It almost always backfires. If every promotion case is obvious to the org, you avoid a lot of unnecessary drama. If a termination or “not meeting expectations” review is a surprise, it is a total management failure. A big counteroffer rarely works when someone is already leaving. By then it is too late. It is also unfair and proves the person was probably underpaid before. The only way to build a great team is to hire people better than you. Every hire resets the cultural and talent average. Aim to increase talent density, because otherwise it will naturally go down. B players hire C players. But even A players make hiring mistakes. Correct them quickly or they become a virus in the org. It only takes one unaligned or bad performer to destroy the motivation and momentum of a full team. Bad fits are rarely isolated incidents. There are always multiple signs. Performance issues will eventually become obvious to everyone. Focus on the middle performers. High performers and low performers are obvious. The people right on the line create the most problems because they are usually acted on too late. Top performers compare themselves against the very best people in the company. Reassure them when they are doing great work. On the other hand, underperformers compare themselves to other underperformers. That is how they convince themselves they are doing fine. The best people can stretch a lot. They often rise to the challenge. But watch their limits before they burn out or become the bottleneck. People usually do not burn out because of hard work. They burn out because they are doing shitty work or working with shitty people. Perfectionists can be great, but startups are hard for them. Help them embrace chaos. Things will break. The job is to keep reprioritizing and stop small cracks from becoming big fires. Even the best people have rough patches. Be empathetic, accommodate, and provide early feedback. But be clear that previous performance is not a guaranteed seat forever. Real startup people are not just the ones who enjoy the early stage. They are the ones who keep adapting as the company changes. You cannot build a company for everyone. The earlier you accept that, the more aligned your team will be. Write the company values down and never stop talking about them. Early employees shape the culture more than any values doc. Early employee morale is a good indicator of the state of the culture. Culture needs policing, even (especially) when things are going well. Have zero tolerance for illegal behavior and misconduct. Follow first principles, but remember that one of the best parts of starting a company is building a workplace you would have loved to work at. Do not be afraid to be unique. Don’t network for the sake of networking. It is mostly bullshit. Build great things instead, and the opportunities to meet and recruit interesting people will show up naturally. It is harder to run a 20-person org than a 100-person org. Between 20 and 40 people, systems break and communication lines grow exponentially. Fix the systems and org structure so you can keep scaling. Teams survive being small better than they survive unclear decision-making. Poor performers also have a harder time hiding in smaller teams. If there is no DRI, do not expect it to get done. Shared ownership usually means no ownership. Shipping velocity is a cultural advantage, and it almost always improves morale. If it is important, write it down. Writing is one of the most powerful leadership tools. Founder osmosis stops working around 50 people. Write things down and overcommunicate. Transparency in times of crisis pays dividends. Employees want to be treated like adults, and it builds trust. The same applies externally. Numeric goals are proxies. Missing one is not the end of the world if you learn. But beating the number while ignoring what is broken underneath masks critical issues. In order to preserve talent density, do light 30/60/90-day performance management for new hires. It forces early feedback and avoids surprises later. Do not listen to people who say founders should not waste time interviewing. That is bullshit. Hiring is the highest-leverage thing anyone at the company can do. Founder interviews help in three ways: you meet people you may not work with directly, candidates can ask direct questions, and hiring managers stay accountable. If the founder says no, there was probably a problem earlier in the process. At a certain seniority, it is not about who plays with computers best. It is about who knows the business and customers best, influences the team, and works autonomously without needing management. Create a culture where everyone is encouraged to talk to users. The more they hear the pain directly, the better and faster they will build. Always optimize for simplicity at startups: product, processes, systems, compensation, recruiting, everything. Optimize for simplifiers and avoid complexifiers. Small teams ship faster. This has always been true, and it is even more obvious in the age of AI. Reduce team size, give teams clear ownership, and have managers spend most of their time with the teams that are struggling. Praise people who go above and beyond and do things outside their scope. But a side quest should never replace the main quest. Keep an eye on median tenure, especially during rapid hiring. Sometimes you need to cool down before the team is ready to ingest and onboard more people. Reorgs are inevitable in a growing startup. Build a culture that understands they are necessary, not automatically negative, so you avoid unnecessary emotional damage. By the time a reorg is obvious, you are probably late. Re-evaluate the structure at least twice a year. When doing reorgs, start with an MVP: involve as few people as possible, make as few management changes as possible, and have a clear rollback plan. If you reach PMF and have built a decent pizza team, you have probably achieved more than most of your advisors. Be open to feedback, but do not let imposter syndrome override your gut. Only truly listen to the people who have actually done it. Get a real support system: coaches, other founders, people who understand the game. Family and friends can help, but they will never fully understand, and it is unfair to expect them to. The best way to spend less time managing bad people is to spend a lot more time hiring the right people. It’s never the smartest team that wins. It’s the one that persists, keeps going, day after day, doing thankless work to build something people want. Most companies fail. Life is too short to spend years building with people who drain you. Build a team you are inspired to work with and achieve the impossible.
They say only one out of 1000–2000 startups becomes a unicorn, and that only 1% of humans will ever finish a marathon. If you had asked my mother, though, she would have told you it was a thousand times more likely I’d build a billion-dollar tech company than finish a marathon. And I would’ve agreed. I was that kid in school with straight As who still almost failed PE. Two laps around the soccer field and I’d be hyperventilating. On New Year’s Eve last year, my co-founder Jacob slipped on the snow and broke his ankle. A gnarly injury. Fast-forward to March 1st, and he announces to the entire company and our investors that he is going to run the California International Marathon on December 7th. And also, he invited people to join him in his crazy adventure. I considered it for a split second and literally laughed out loud. This guy will do it, I thought. He’s delusional and stubborn enough to crawl the last 10 miles if necessary. But me? No chance. The longest run of my life was a single 10K, once, years ago. I ran it, and then immediately retired from the sport. But the idea stayed in the back of my mind. If Jacob crippled, needing surgery, with months of PT, could commit to running a marathon… what excuse did I realistically have? I was healthy. I had a head start. And honestly, after the twins were born, my exercise routine was basically nonexistent. Running was something I could technically do anywhere. My wife, fully aware of how much I hated running and how hard this would be for me, became a supporter. So I downloaded Runna. And I ran. I hated it. Deeply. Running felt like the most boring, repetitive, form of suffering ever invented. But something weird happened: I started seeing progress. Three miles stopped feeling like a death sentence. Then I ran 10. Then one random morning before giving a conference talk, I ran a half marathon by myself. And it didn’t even feel that hard. I started waking up earlier and earlier to get my mileage in before the morning meetings. Discipline compounds quietly, until suddenly you’re a different person. This year I traveled a lot. Yet running turned out to be the easiest habit to keep. I ran more than 900 km in 18 different cities. Running became a new, exciting way to explore a city. A nice way to start the day with a small win before all the startup chaos. This weekend, we did it. We ended the race in way more pain than we probably should have, but we crossed the finish line. And the biggest lesson I learned, bigger than training plans, pronation, and fueling… is this: You need to be a little crazy and do hard things. And that’s kind of the whole point. Life isn’t about being the best in the world. It’s about being the best version of yourself. Expanding what you thought your limits were. Rewiring your internal narrative from “I could never do that” to “actually, maybe I can.” I’m insanely proud of Jacob for this comeback story, and grateful (even if involuntarily) that he dragged me into another ridiculous adventure. It was worth it. And maybe this story nudges you toward something you’ve always dismissed as impossible. After running these 26.2 miles, building a decacorn feels easy. Okay, not easy, but you get the point. Will I do it again? I don’t know. If I had put this much time into surfing, I would suck a lot less at it and probably enjoy it more 😅. But I’ll keep running. It keeps me fit, clears my mind, and makes me a better version of myself. Which, in turn, helps me be a better founder, partner, and dad. Special thanks To Runna, genuinely a fantastic training app (and RC user!). To Marina, for the endless support and the childcare coverage while I disappeared for very long runs. To Andrew, Harlan, Bobby, Susannah, Sarah, Nacho, Chris, Mica, Matt, and Olga, for the advice, motivation, and for putting up with my running updates.
2024 has come and gone, and it’s time for my annual post. What a year for startups—like squeezing five regular years into one. Do you remember the Apple Vision Pro, the DMA regulation, founder mode, or the o1 launch? All of that happened in just the last twelve months. It’s also been wild at RevenueCat. My journal is full of stories that could fill a whole book or even a few HBO Silicon Valley seasons. Some are inspiring, some are hilarious, and others are honestly gnarly. Due to limited space, the need for context, and respecting everyone’s privacy, I’ll cover only the most interesting topics at a high level. Looking back, it was a good year for RevenueCat. Actually, a great one. Perhaps our best since 2020. We have plenty to celebrate: We accelerated again, and we hit our C10 revenue plan. We made our first acquisition and welcomed an amazing founder to the team. We signed our first multi-million-dollar contracts. We went to more than 20 events around the world… …including hosting our own conference, featuring its own award ceremony. We became the #1 payments SDK on iOS. Our swag went to 11. We launched over 80 user-facing features. We showed up in Times Square and along Highway 101. We raised a mini Series C and welcomed two new board members. We landed in Japan for the first time. Our API grew beyond 2B requests per day. We are processing nearly twice the TAM we had when we started the company. OpenAI is a friend of the cat. We continued building a winning team. We hired people who were on my to work with bucket list even before we started the company. By all the metrics, 2024 was our year of shipping and selling. We absolutely helped developers make more money. My role If you compare our progress to the goals I wrote about in last year’s blog post, it’s clear we succeeded. But the journey itself was a lot rockier than I had imagined. Many things didn’t go as planned, somes hires did not work out, and some strategy changes were really hard to push through. At the start of the year, besides my usual responsibilities, I also set four personal goals to help me scale with the company. I wanted to: Ship code more consistently. Talk to at least one customer every single day. Get more involved in areas outside of engineering. Stay very close to my co-founder Jacob, giving him my full support. I completely missed goal #1. Honestly, that hurts because I love building software. But I’m not too upset about it—our customers care that the team ships, not that I personally do. And in a way, I did help the team ship. As for the other three goals, I hit them, at least based on the company’s results. Still, my self-perception wasn’t always great. I found myself acting much more like a co-founder/executive than a CTO. Some weeks were brutal, with constant context switching across tasks and teams I didn’t always enjoy. At one point, there were over 60 people in my org, spread all around the world, which is pretty intense for an introverted computer kid. A lot of bullshit escalates to the top, making me question my entire existence some days. And then life threw serious personal emergencies at some of our team members too. Like I said last year, life is what happens when you’re busy building your startup. As we got closer to 100 people, it was statistically unavoidable that we’d face a few life-changing traumas—sometimes several all at once. As a founder, you need to be supportive and empathetic, but also protect your mental health. As a human, it’s tough. Add in a couple of two-year-olds who were often sick and not sleeping, and it felt like a ticking bomb. Did I burn out for the first time in my life? I don’t think so, but it got close. I’m confident being a founder (and having a co-founder) kept me going. I care too much and must stay resilient. If I’d been just an employee, I might have tapped out. But enough about the tough parts. Aside from being a professional BS handler, here’s how I spent most of my time: Lots of travel This was the year I traveled the most in my life—and looking back, I probably should have traveled even more. I visited customers, helped with sales, conducted executive interviews, and spoke at a few conferences. It’s hard being away from two little kids, but each trip turned out to be worth it. Support One of my biggest worries this year was our support function. Everything was fine, but our Support Engineering Manager was going on parental leave, and the bus factor was scary. I’ve seen support crises before—they’re not fun. It wouldn’t have killed the company, but at our size, it might have forced us to pull senior engineers into support and slow down our product velocity. Time was short, so we tried a few things that worked: We hired two new Developer Support Engineers who already knew our product—former customers! Their onboarding was smooth, and they hit the ground running. We split the support team into two pods with their own leads. Each pod handles certain tickets, and they collaborate with each other instead of relying too heavily on one person. We finally set up our first on-call rotation for emergencies. Sales and post-sales Reviewing sales and implementation calls, giving technical input, collecting enterprise customer feedback for product and engineering, joining calls, and even doing some in-person visits. Writing more As our team continues to grow across the globe, not everyone has the same direct interaction with me or Jacob as before. A lot of our culture and collaboration style was once passed through observation, but now needs to be written down to reach everyone faster. These days, my code editor is basically replaced by Google Docs. I’ve been publishing more internal and external documents—like our Engineering Strategy and an updated How to Work with Miguel. Product delivery We still have a few details to refine, but our founder Shipping and Timeline reviews have been valuable. It gives Jacob and me a high-level view of everything in progress, lets us offer feedback, and helps us dig deeper where needed. It’s a great way to see each team’s capacity, find bottlenecks, keep a sense of urgency, and deflate anything that’s not truly important for the customers. Re-orgs This year brought a couple of big reorgs in product and engineering. Overall, they went well, but the puzzle gets more complex with each new piece. We created sub-teams to narrow their focus and keep things running smoothly. For the first time, we had a couple of management layers between me and our ICs. One major change was shutting down our Enterprise/Reactive team. The idea was solid at first, and they delivered plenty of value, but eventually they became the random tasks team. Our new plan is to reinforce the rest of the teams: quick enterprise requests go to the right team to handle them reactively, while bigger projects move to the main roadmap (which keeps us disciplined). The engineers from that old team will help bootstrap new teams as we hire in 2025. Hiring Our engineering hiring goals weren’t super ambitious, but we still reached them. The pace was a bit uneven, and some roles took longer to fill than desired. However, when Hiring Managers took ownership of the process (with recruiting as a support) it made a huge difference in the quality of our candidates. We also brought back the founder interview stage: Jacob or I spoke with every single candidate before making an offer, and we plan to keep doing this for the foreseeable future. Random founder stuff Not my main focus, but I still spent a fair amount of time handling people-related topics, operations, investor, customers and partners relations, fundraising, company policies, planning, etc. Learnings: deepened insights On culture Shipping is king. Yes, deadlines are stressful, but failing to ship and getting stuck in endless debates is far worse. It’s depressing. If someone isn’t a good culture fit, it will be more than a single incident. Over time, it becomes pretty clear to everyone. Top performers tend to measure themselves against the very best in the company. Reassure them they are doing a great job. On the other hand, those who underperform will look to other underperformers to gauge their own progress. Even top performers will struggle if they don’t fully align with the vision. Nothing beats talking to customers. Encourage everyone to do it. Better in person. Most managers don’t have a strong incentive to be strict, so finding the right balance takes a lot of calibration. Only once everyone is aligned, you can truly delegate. On hiring Managers hate hiring because it’s binary: a lot of “no”, but eventually one “yes” can change everything. Staying consistent really helps. Simple things, such as weekly updates keep everyone accountable. People management sucks. If someone’s main motivation is to be a manager for the title, or so they can “lead,” that’s a red flag for me. Best managers end up being those who never planned on becoming one in the first place. They actually roll up their sleeves and can do the work. Big ideas are great, but they need to be executed. This matters even more when it comes to executives. A truly great exec can change your life and it will feel like a brand new company. Given their influence, anything less than great will eventually turn into a big mess. Spend time with executive candidates in person. Watch how they work and make sure they’re real builders. Previous founders and true engineers are usually a little bit de-risked, but they’re still not guaranteed. I also like to write a very detailed onboarding doc, clarifying context, expectations, and what success or failure looks like. Having them write a 30/60/90-day plan helps us all align. I’ve learned not to rely on their past pedigree. The real key is their glass eating endurance. On company building Re-orgs are inevitable at a growing startup, and they will feel scary or emotional for people who aren’t used to them. I find it helpful to be super clear about why we’re doing it, and to share the fallback plan if things don’t work out. But I’ve learned that by the time you think you need a re-org, you’re already behind. We now plan to reassess our team structure twice a year for optimal shipping. A numeric goal (like an SLA or revenue target) is just a proxy. Missing it isn’t the end of the world if you learn in the process. But if you surpass it without recognizing what’s broken underneath, you’ll be masking critical issues. Perfectionists are great, but can have a tough time at startups. Some do fine if they’re focused on one specific thing or working as an IC. But as soon as they have to juggle multiple tasks, the chaos can feel overwhelming. Help them embrace it. Things will break. It’s about continuously reprioritizing, and stopping small cracks from becoming big fires. No agenda == no meeting. Synchronous time is expensive. The only exception is the occasional unscheduled call. After you reach around 50 people (especially in a remote setup), documenting every process change becomes crucial. I’ve learned the hard way that simply talking about a new process isn’t enough. Founders can’t talk to everyone all the time anymore, and misunderstandings or gossip can spread fast. Not everyone will read everything, but at least there’s a single source of truth to reference. Best people can stretch quite a bit—they’ll often rise to the challenge. But it’s wise to keep an eye on their limits before they burn out or become a bottleneck. On scaling as a founder A great EA is life-changing. Family will be supportive, but it’s not fair to offload all the stress on them. They will end up feeling helpless. Having a solid co-founder, a network of peers, or a good executive coach makes a world of difference. Founders are the ultimate guardians of the culture. It’s constant work, and it will feel relentless—especially when things are going well and it’s easy to get entitled. The best team members will help uphold the standard, but you cannot expect them to do all the policing. At this stage, it’s stupid not to level up your lifestyle in ways that reduce stress or save time. This might include childcare support, having a second car, investing in a better mattress, or hiring help with housekeeping. The startup is bigger than its founders, and the goal is to continuously remove yourself from the critical path. Still, it’s easy to forget that, as a founder, you literally brought everything into existence from thin air. Imposter syndrome often creeps in when you step outside your core expertise, but if your gut feeling is strong, it’s worth paying attention to. Stay open-minded, yet remember that no one knows the company quite like you do. The future Next year is going to be another big one. We’ll keep shipping and selling, while finally tackling our design and UX debt. We’ll keep investing heavily in our infrastructure. Not just for reliability, but also for real-time data. We want RevenueCat to feel fast, accurate, and easy to use. We’re also upgrading our self-serve and enterprise support, aiming for a truly world-class experience. In many ways, we’re finally seeing the original vision Jacob and I had back in 2017 come to life. We’ll be launching new product lines too, and if we execute well, we will be just a couple of years away from hitting $100M in revenue. We’ll keep building a winning team. We’ll hire about 45 people, 30 in Engineering, Product, and Design. It’s a challenge, but totally doable. As for me, my personal goals haven’t changed much, but my perspective has. Jacob and I used to joke that being happy and winning can’t happen at the same time. But why not? We’re in a privileged position to shape our own path and change anything we don’t like. After a lot of reflection and coaching, I realized I was simply too hard on myself. I was feeling depressed by the constant BS even though we were winning. A hack that helped was working with my EA to set weekly goals and then sending a public update to the full team. It let me see the real progress behind all the drama and back-to-back meetings and stay transparent with everyone. Next year, I’ll avoid meetings before 9 AM, keep an eye on calendar creep, and hold myself accountable to exercise and doing what helps me decompress. I know, it’s obvious. I also plan to travel more. Especially to the Bay Area, which is clearly back again. Meeting up with other founders and customers is always worthwhile. Another thing that made last year tough was having half my direct reports on parental leave for about half of the year. Now they’re back, and I can feel the momentum returning. Jacob has also taken over product again, now that he’s stepped away from directly owning operations and people. Increased shipping velocity has been noticeable. We have all the pieces in place. All that’s left is to keep pushing forward: shipping, selling and enjoying the ride. If there’s one thing I learned in Silicon Valley, it’s that no goal is too crazy if you refuse to give up. I really hope you enjoyed reading this post. As always, my intention was to share it with complete honesty and transparency, avoiding the hype that often surrounds startups. If you are facing similar challenges and want to connect and share experiences, please do not hesitate to reach out on Twitter or shoot me an email! Special thanks to my co-founder Jacob, my EA Susannah, the whole RevenueCat team, and our valuable customers. I also need to express my eternal gratitude to all the CTOs and leaders who have been kind enough to share their experiences over these years. Shoutout to Dani Lopez, Peter Silberman, Alex Plugaru, Kwindla Hultman Kramer, João Batalha, Karri Saarinen, Miguel Martinez Triviño, Javi Santana, Matias Woloski, Tobias Balling, Jason Warner, and Will Larson. Our investors and early believers Jason Lemkin, Anu Hariharan, Mark Fiorentino, Mark Goldberg, Andrew Maguire, Gustaf Alströmer, Sofia Dolfie, and Nico Wittenborn. I want to convey my deep gratitude to my amazing wife, Marina, who has been my unwavering source of inspiration and support from the very beginning, and for blessing us with our two precious daughters. I cannot close this post without thanking my mom, who made countless sacrifices to mold me into the person I am today. I promise you will look down on us with pride the day we ring the bell in New York. I love you dearly.
I’m back in Spain for my brother’s wedding. I rarely visit during the summer. The heat in my hometown is brutal, around 40 degrees Celsius (over 100 Fahrenheit for my imperial friends). Most people escape to the coast, just like my family did when I was a kid. I haven’t been here in years. As I drive along the coast, I find myself reflecting on a tweet about money and happiness, a vivid memory pulls me back in time. It’s August 22nd, 2007. The iPhone, the first real smartphone, has just been announced. It’s so cool, but of course I cannot afford it. It’s not even going to be released in Spain. I’ve just gotten my driver’s license, and I’m about to dive into my third year of Computer Science. I set up my clunky TomTom navigator knockoff, and hit the road. I’m on my way to meet Marina for our first real date. She’s cool, pretty, and kind. She likes the same music as I do, and even has distant relatives in California, the place we jokingly plan to visit someday (if I ever get enough cash). I’m listening to a pirated Blink-182’s self-titled CD. Pop-punk is pretty niche in the south of Spain, and it’s dying. Blink-182 has split up, and I missed my window to see my favorite band live. The Atlantic Ocean is as flat as a lake. This corner of Huelva’s coast is sheltered from any real waves, a stark contrast to the world-class surf breaks I drool over in magazines. And suddenly, reality hits: my childhood dreams of building a tech company in Silicon Valley, while vacationing in Southern California feel impossibly far. Even getting through my degree feels like a pipe dream. School isn’t fun anymore. It’s grueling, especially the parts I thought I’d enjoy, like algorithms and Data Structures. I might never become a Software Engineer. I feel stuck, trapped by my lack of direction. I am seriously considering quitting. But no degree means no job in the US, and good tech gigs are rare here in Spain. The only cool company is Tuenti, a new startup that is cloning Facebook. I’m nowhere near smart enough to land a job there though. Flash forward to today, 17 years later. It’s almost laughable to think about how hopeless things once seemed. Even now, it doesn’t feel like I’ve “made it.” The path and the results look nothing like what teenage me envisioned, but somehow, I’m realizing I’ve kind of checked off every box. I married Marina, and we live in Southern California with our two beautiful identical kids. We’ve become American citizens, and I’ve lived in the Golden State for nearly a third of my life. I’ve worked as a Software Engineer at a Silicon Valley startup, learned from the best, and found the best co-founder I could ask for. We launched our own company. Smartphones? They’re in everyone’s pockets now. Our product is in a third of all new apps shipped in the US. We’ve helped developers reach millionaire status, and we’ve made more money than I ever thought possible. But I’ve learned that a lot of money is a relative term. Somehow, I managed to hire insanely talented engineers—a bunch of them, ironically, from Tuenti. Blink-182 is back together, and I’ve been fortunate enough to see them live five times. I’ve even bumped into Tom Delonge after surfing world-class waves a few times. I’m literally just realizing how surreal all of this is. I tend to get caught up in the chaos of what’s next—the next big fire, the next goal—but sometimes you’ve got to stop, be present, and reflect on how far you’ve come. It wasn’t easy. It wasn’t without loss, sacrifice, and a fair share of doubts. Am I truly happy? Maybe not in a perfect, all-the-time kind of way. There are external things humans cannot control. But when I look at my life, I realize there’s no real reason not to be. The journey has been was worth it so far: the ups, the downs, the unexpected turns. So, here’s to your journey, whatever it looks like. Keep going, keep dreaming. It might not turn out the way you envisioned it, but it’s only impossible if you quit.
More in programming
As with my last post on AI, let me open with a statement: Just because most people hold AI a certain way, doesn’t mean that we always must, either now or in the future. As I noted in that piece, and my shades of gray post, I am well aware — and agree with — … Continue reading Must we always use LLMs this way? →
TokyoDev has grown substantially over the past few years. We’ve expanded our community, dramatically increased the scope and frequency of our events, and have curated a library of articles for international developers. Despite all that, the way we run the business hasn’t changed much. I’ve continued to coordinate most of these activities myself, making the final decisions and keeping everything connected. In short, TokyoDev cannot run without my daily input. That approach worked well when TokyoDev was smaller, but it’s increasingly limiting how much we can accomplish. To help the business grow further, I wanted to find someone to take over some of my responsibilities and bring a fresh perspective. This is a significant step for me personally, as while I have worked with many contractors over the years, I have never actually hired a regular employee. Most importantly, I wanted to ensure that this person was someone I could trust to understand what TokyoDev stands for, and to make decisions in line with our philosophy. So I’m happy to announce that Scott Rothrock is joining TokyoDev full time as our Head of Operations. About Scott Scott has lived in Japan for nearly 20 years and has worked as a software engineer in multiple industries and environments, including small Japanese-owned businesses, overseas employers, and international companies based in Japan. Until the end of October 2026, he was the head of the Japan Markets team at Kraken Technologies, where he led an international team of software engineers in delivering complicated, regulated products on strict timelines for Japanese electricity and gas retailers, while also ensuring compliance with evolving organizational and global standards. He’s made a name for himself both inside and outside Japan as a kind, effective mentor who can cultivate great engineers and leaders. Scott’s previous role in TokyoDev Some of you may already know Scott in another capacity, as he has been involved with TokyoDev since 2022. He began as a community volunteer and later became our community manager, which also included responsibilities such as managing our article pipeline from submission to publishing. When I created TokyoDev’s Discord, I had no previous experience running an online community. Scott joined soon after I started and began helping other members, stepping in when people behaved inappropriately, and configuring our roles and permissions and safety features. I was impressed by his initiative and asked him to become an official moderator in January 2023. Outside of his role as a moderator, Scott has always pushed TokyoDev to grow; for example, he arranged internet events such as livestreamed AMAs and interviews. He organized TokyoDev’s first meetup as a volunteer in February 2023, which taught me that there was interest in TokyoDev events outside of the internet. By the end of 2023, I had brought him on as our part-time community manager. What I saw throughout his tenure was that Scott continued to take initiative in expanding TokyoDev. Scott was one of our first external contributors, writing about his experience living with a disability in Japan. He encouraged me to expand and refine both our editing and submission processes so that we could reach out to even more contributors and platform their perspectives. The editorial team now consists of him and Rebecca Callahan, and they’ve had a hand in every article that TokyoDev has published. In other words, since 2022, Scott has shown that he cares about TokyoDev as much as I do. He is invested in what we do and why we do it, and shares my vision for what TokyoDev can become. What changes now Scott’s experiences as an engineer, a mentor, and a leader make me confident that, as our Head of Operations, he will continue to help TokyoDev mature. A big part of what has made TokyoDev successful is that I see the software developers who use our site as my peers and genuinely want to help them. Scott shares that perspective, and will join me in ensuring that TokyoDev remains true to its principles while we grow. So what changes in the short term? Nothing dramatic. I will teach Scott about managing TokyoDev as a business, and he will document our processes and products as a part of that learning. He will also look for areas of improvement while ensuring that we remain compliant with regulations and labor law. Over time, I will hand over some other responsibilities. I will continue to run TokyoDev, but TokyoDev will become less dependent on me for its day-to-day operations. Long term, I’m excited about what this will enable us to do. TokyoDev has always been about helping international software developers build successful careers in Japan, and bringing Scott on full time puts us in a much better position to continue doing that. We look forward to writing the next chapter of TokyoDev together.
Kidz Fun Art is a drawing, colouring and animation app for kids that I’ve been building since 2021. It runs in the browser also as a simple wrapper app on iOS, iPadOS and Windows. It wasn’t getting a great click through rate on Google, even for people who directly searched for it. So, for two days I took a hard look at how fast it loads and how search engines see it. It wasn’t flattering. This post covers what I found, what I changed and what the graphs say now. Short version: on a simulated slow phone, the homepage’s Largest Contentful Paint got about 2.6× faster (15.9 s to 6.1 s) and its first load is about 82% smaller (4.2 MB to 0.75 MB). I also fixed a set of SEO mistakes that are, frankly, embarrassing to write down. I’ll write them down anyway. Part 1: Google had no idea what the site was for I started by reading 16 months of Google Search Console data. 9,380 clicks in total. About 9,200 came from people who had typed “kidz fun art” or a close spelling. People searching for what the app actually does (“coloring app for kids”, “ai art for kids”, “make a comic book”) sent the site 164 clicks. In 16 months. Total. When there was a relevant page, Google ranked it well. The site was #1 for things like “drawing app for kids ipad” and a German query that means “paint by numbers app without ads”. There just weren’t many relevant pages. Then I looked at the code, and the cause was obvious. The homepage <title> was “Kidz Fun Art” in all 12 languages. That’s a fine name, and a terrible title. It tells a search engine nothing. The homepage’s first <h1> was the pricing table’s “Choose your experience”. I was, in effect, telling Google that the most important thing on my homepage was the checkout. Every blog post had the same meta description: a generic line about “news, updates, tips”. Each post’s front matter already had a perfectly good excerpt field that nobody read. Blog posts had two <h1>s: the site header and the post title. There was no structured data at all. The sitemap that redirected every single URL This one stings. The sitemap is the one file whose whole job is to say “here are my URLs, please index them”. Mine listed 17 URLs, and every one of them redirected. The sitemap build used an environment variable that resolved to kidzfun.art. The site lives on www.kidzfun.art, so every URL got a 308. Only the English blog posts were listed. The other 11 languages appeared only as hreflang alternates, which pointed at redirecting URLs too. There were no <link rel="canonical"> tags on any page and no hreflang in the page <head>. Google was left to guess which URL was the real one, and it guessed wrong a lot. What I changed: The sitemap is now built on https://www.kidzfun.art, with 204 URLs: every home page, blog index, blog post, About page and gallery page, in all 12 languages. Each one lists all of its language alternates plus an x-default. A shared SeoLinks component adds an absolute canonical (www, no query string) and the full hreflang set to every public page. The ?v= cache-busting URLs that had been showing up as duplicates now canonicalise to the clean URL. /xx/blog/yy/... URLs, which returned a 500 in production (oops), now 308 to /blog/yy/.... Login, account, debug, export and embed pages send X-Robots-Tag: noindex, follow from next.config.js, so they stop using up crawl budget. robots.txt now mentions the sitemap. Novel idea. Why Google skipped half the site Search Console’s Pages report had 93 of 174 known pages not indexed. Every reason on that list traces back to the mistakes above: “Page with redirect” (22): that sitemap, plus internal links to the non-www host. “Duplicate without user-selected canonical” (18): I hadn’t selected any canonicals. Fair cop. “Crawled, currently not indexed” (39): mostly translated posts that Google reached through redirecting URLs, plus thin pages like /login. “Discovered, currently not indexed” (12): Google found these and decided they weren’t worth a visit. With no sitemap entry and no hreflang, I hadn’t given it a reason to. On-page fixes Titles and descriptions: Each blog post got its own seoTitle and description, in all 12 languages. The meta description now comes from the post’s excerpt, which is what that field was for all along. The About pages take their title and description from their own localized Markdown. They had been sharing an English title and a generic description. One <h1> per page: A # heading inside a post’s Markdown now renders as an <h2>, so the post title is the only <h1>. The About page opts back in with a keepH1 prop. Its Markdown heading is the page title. This fix arrived in two parts. The first part left the About page with zero <h1>s. I noticed, eventually. Structured data and social tags: JSON-LD for the home page (the app), blog posts (articles) and the embedded videos. Open Graph and X/Twitter tags on every public page, so shared links get a proper card. A real 404 for deleted gallery images: The AI gallery shows a friendly “AI Artwork Not Found” page when an image has been deleted. It used to return 200 OK, which Google calls a “soft 404” and dislikes. It now returns a 404 with noindex, and a 503 if the Firestore lookup itself fails, so a database hiccup tells crawlers “come back later” rather than “this is gone”. Part 2: Making the homepage fast The homepage is the app. It works offline, so every dialog (save, stickers, colouring pages, “get an adult”, “no wifi”) is server-rendered into the HTML up front. That’s a deliberate trade-off, and I kept it because I want new users to be able to immediately be able to start drawing as soon as they launch the app. What I hadn’t thought about was what it meant for the network. What the homepage downloaded before the app could start I measured the live site with a Lighthouse-style mobile profile: slow 4G (1.6 Mbps, 150 ms latency), 4× CPU slowdown, empty cache. First load: 4.5 MB over 198 requests. The homepage HTML alone was 358 KB, with about 77 <img> tags in hidden dialogs. The browser dutifully fetched every one of those images. The script that starts the app (main.min.js, 191 KB) sat at the very end of the document, so the browser found it last and gave it whatever bandwidth was left. The app script finished arriving at about 14 seconds. The CPU was not the problem. Every long task was under 300 ms. This was purely about bandwidth and request order. I had built a very polite queue and put my own app at the back of it. Watch the queue The waterfall is a simplified illustration. The milestone times (first paint, LCP, load) are measured: slow 4G + 4× CPU, local production build, median of 3 runs. My Largest Contentful Paint was the “Contact support” link The canvas doesn’t count toward LCP, and the toolbar buttons are small. So on a slow load the largest thing painted was… the loading dialog. The loading dialog fades in its “Taking a while? Contact support” text after 5 to 7.5 seconds. On a slow connection, that text became the page’s LCP element, at 15.9 s. I was measuring my page speed by how long it took to suggest the user complain about my page speed. There’s a lesson in there somewhere. The fix wasn’t to change the dialog. It was to make the app start sooner, so it paints before that text ever appears. What I changed Preload the app script. I added <link rel="preload" as="script"> in <head> for main.min.js and errorHandler.min.js. The <script> tags stay where they were, so execution order doesn’t change. The browser just starts fetching them before any image. This one line did more than anything else on this list. It’s a little humbling. Turn the three dialog GIFs into MP4s. Three animated GIFs: an arrow pushing pictures into a tablet (927 KB), a dancing rainbow pencil (650 KB) and a paper plane (305 KB). That’s 1.9 MB of decoration in dialogs most visitors never open on their first visit. I re-encoded them with ffmpeg: H.264 High profile, -preset veryslow -crf 20, yuv420p, +faststart, constant frame rate taken from each GIF’s frame delay. The commands are committed as scripts/gif-to-mp4.sh. The result is 130 KB in total, with SSIM between 0.988 and 0.993 against the originals. The pencil needed tpad=stop_mode=clone:stop_duration=0.2, because ffmpeg’s GIF reader drops the final 250 ms hold and the dance lost its big finish. The new <video autoplay loop muted playsinline> tags render at exactly the same size and class as the old <img> tags. Alt text moved to aria-label. Locked colouring thumbnails were full-size PNGs. In the colouring page picker, locked pages used the full-size colouring PNG as their background image, inlined into the HTML. That came to about 1.3 MB on every first visit, to draw thumbnails in a dialog that was closed. They now use the small image, set when the picker opens, like the unlocked ones always did. Sticker thumbnails wait their turn. I tried loading="lazy" first. It didn’t help: Chrome fetched the images before the stylesheet that hides the dialogs had arrived, so as far as it knew they were visible. Sticker thumbnails and the media library’s YouTube thumbnail now use data-deferred-src. They load 3 seconds after the load event, or as soon as their dialog opens, whichever comes first. The service worker preload starts after load. The offline preload queue (about 2 MB of colouring pages and stickers) used to start while the page was still loading and compete with it. Now it starts after the load event. Same files, same offline result, no fighting for bandwidth. Analytics is async. Nothing waited for it, so nothing needed to block on it. Cache headers. /images/*: max-age=86400, stale-while-revalidate=604800. It had been max-age=0, so every image was re-checked on every visit. Versioned /js, /css and /addToHomescreen files are immutable for a year in production. Offline still has to work Offline support is a core feature, so “just don’t download it” was never an option. Some of the changes above put it at risk, and a couple of things turned up along the way: Safari plays video from byte ranges. Safari requests video with Range: bytes=.... Answer that with a full cached response and the video won’t play. The service worker now answers Range requests from its cache with a proper 206 Partial Content slice (lib/util/rangeResponse.ts, with unit tests). First-visit gap: on a first visit the service worker isn’t controlling the page yet, so dialog images only reached the offline cache on the second online visit. The page’s own dialog images and videos now go to the front of the offline preload queue on the first visit. I nearly downloaded my whole site, 12 times over. The service worker cached every <link href> it found in the page. The new SEO work had just added canonical and hreflang <link>s pointing at all 12 localized homepages. So every new visitor would have downloaded about 12 extra homepages, in languages they don’t speak, “for offline use”. I caught it before production. The service worker now skips rel=canonical and rel=alternate. Safari stopped the service worker mid-download. The old preload queue ran on timers after the request had been answered. Safari considers an idle service worker fair game, so it stopped it after the first few images. The page now sends images in batches of 10, and the service worker caches each batch before it replies. A page lock-up I’d never noticed. resizeDialog added a new “image loaded” listener every time the window resized. With lots of images loading at once, the listeners multiplied until the page locked up. It now attaches one listener per image, which, in hindsight, is how many it needed. Part 3: The blog Blog index cards used the full 1920 px screenshots as covers, up to 500 KB each, in a box about 200 px wide. Each card was a little billboard, shrunk down by the browser on every visit. Covers now go through next/image with sizes that match the actual card widths, so the browser gets a resized WebP. The first few cards get priority. The rest load lazily. The first sizes hint was too small at some widths and made covers blurry. It now matches the real card widths, up to about 630 px between 769 px and 1028 px wide. Post pages: The cover image gets fetchpriority="high", and images further down the post load lazily. Five images were recompressed in place, keeping the same filenames and dimensions. The PNGs came out about 4× smaller and the JPEGs about 40% smaller. I deleted a 1.1 MB cover.png that nothing referenced. All 12 translations of that post used cover.jpg. The PNG had just been sitting in public/ taking up space. Results on the slow 4G profile: /blog LCP went from 13.3 s to 1.8 s. A typical post went from 3.9 s to 1.7 s. The gallery didn’t get faster, on purpose. It got a 5-minute edge cache and a cached Firestore image count, which fixed its slow server responses. I decided not to change its 20 full-size PNG thumbnails, so its lab LCP barely moved (8.4 s to 8.6 s). That’s a choice, and the chart owns it. Part 4: Lighthouse homework After the speed work went live I ran Lighthouse on the production homepage (mobile) and cleaned up what it flagged. Performance stayed in the low 70s, so I have some more work to do, but it’s moved nicely in the right direction. Part 5: Telling the search engines Fixing the site is half the job. The other half is getting crawlers to come back and notice. Google Search Console: Resubmitted the www sitemap. Clicked “Validate fix” on “Duplicate without user-selected canonical” and on the redirect errors. Requested indexing for the main language homepages and the top blog posts. The quota is about 10 a day, so it’ll take a few days. Wrote down a baseline from the Performance report, so in 4 to 8 weeks I can tell whether any of this worked. Bing Webmaster Tools: Submitted all 204 sitemap URLs through URL Submission. The daily quota is 10,000, so no trickle-feeding needed. Bing’s index also feeds DuckDuckGo and several AI search tools, so it’s cheap extra reach. Most of Bing’s “SEO recommendations” pointed at old ?v= URLs and old titles. They’ll clear as Bing recrawls. What I’m not watching: the Lighthouse score. Google ranks on real-user Chrome data (the Chrome UX Report): a rolling 28-day window, judged at the 75th percentile. So the honest answer to “did it work?” is “ask me in a month”. How I kept from breaking things The app has hundreds of unit and integration tests, all of which still pass (even though they do take over 30 minutes to run). I also manually regression tested all the riskiest changes. Hopefully I don’t make things worse before they get better… Lessons, mostly at my own expense Read your own sitemap. Actually open it and click a URL. Mine had been quietly redirecting for who knows how long. <link rel="preload"> for the script that boots your app is the cheapest big win there is. Browsers fetch resources in the order they find them. If your app script is at the bottom of a 358 KB document full of images, it really is last in line. Check what your LCP element actually is before you try to make it faster. Mine was a “Contact support” link. GIF is an image format from 1987 that I was using as a video format. A real video codec beats it by an order of magnitude at the same quality. try/catch doesn’t catch promise rejections. I knew that. My code didn’t. Every <link> you add to <head> is something your service worker might decide to download. Speed scores are for diagnosis. Rankings come from real users. Fix what the lab finds, then wait for the field data. Epilogue You’re still here? Wow. Cool. After all this, I’m hoping that users notice nothing other than quicker app start times. I’m looking forward to keeping an eye on traffic and retention in the coming weeks. Wish me luck!
Five months ago, we rebuilt our warehouse on DuckDB instead of ClickHouse. We did it because a shared ClickHouse cluster couldn't handle hours-long…