Checkout Extensions turn Shopify's opaque Liquid checkout into something you can actually reason about. React components, typed API, isolated runtime — the marketing pitch is accurate. What the marketing pitch doesn't tell you is that you'll spend the first month learning which target you're allowed to render into and why your state keeps resetting.
The target ladder, in order of pain
Start with static targets (purchase.checkout.block.render). Progress to dynamic ones (purchase.checkout.delivery-address.render-before). Only reach for the customer-account targets when you've accepted that their auth story is its own adventure. Each tier adds a new set of invariants you can't violate without the extension being silently removed from the render tree.
State that persists across targets
You can't share React state across targets — each target is its own extension instance. The correct shared surface is cart attributes via useApplyAttributeChange. Treat cart attributes as your extension's store, and stop trying to lift state.
Deploy pipeline
shopify app deploy promotes the bundle but does not flip the active version — merchants still see the previous one until you publish. Automate the publish step, or you will forget, and your team will spend an afternoon debugging why the fix they shipped hours ago isn't live.
The extension pipeline is a two-phase commit. Forget the second phase and you become the bug.
