App Blocks and Theme Compatibility
Learn how to make your theme compatible with Shopify app blocks, allowing merchants to add third-party functionality without code changes.
App blocks let Shopify apps inject content into themes without requiring code edits. Making your theme app-block compatible is essential for merchant flexibility and app ecosystem support.
What Are App Blocks?
App blocks are special section blocks that apps define. When a merchant installs an app, its blocks become available in the theme editor alongside your theme’s native blocks.
Benefits
- No code changes required by merchants
- Visual positioning in theme editor
- Easy removal if app is uninstalled
- Consistent experience across themes
Making Sections App-Block Compatible
Add the @app Block Type
Any section that should accept app blocks needs the @app block type:
{% schema %}{ "name": "Product Information", "blocks": [ { "type": "title", "name": "Title", "limit": 1 }, { "type": "price", "name": "Price", "limit": 1 }, { "type": "description", "name": "Description" }, { "type": "@app" } ]}{% endschema %}The @app type tells Shopify this section can host app blocks.
Rendering App Blocks
App blocks render like any other block:
{%- for block in section.blocks -%} {%- case block.type -%} {%- when 'title' -%} <h1 {{ block.shopify_attributes }}>{{ product.title }}</h1>
{%- when 'price' -%} <div {{ block.shopify_attributes }}> {{ product.price | money }} </div>
{%- when 'description' -%} <div {{ block.shopify_attributes }}> {{ product.description }} </div>
{%- when '@app' -%} {# App blocks render themselves #} {% render block %}
{%- endcase -%}{%- endfor -%}The {% render block %} tag outputs the app’s content.
Common App Block Locations
Product Page
{# sections/main-product.liquid #}
<div class="product"> <div class="product__media"> {# Media gallery #} </div>
<div class="product__info"> {%- for block in section.blocks -%} {%- case block.type -%} {%- when 'title' -%} <h1 {{ block.shopify_attributes }}>{{ product.title }}</h1>
{%- when 'price' -%} {% render 'price', product: product, block: block %}
{%- when 'variant_picker' -%} {% render 'variant-picker', product: product, block: block %}
{%- when 'buy_buttons' -%} {% render 'buy-buttons', product: product, block: block %}
{%- when '@app' -%} <div class="product__app-block" {{ block.shopify_attributes }}> {% render block %} </div>
{%- endcase -%} {%- endfor -%} </div></div>
{% schema %}{ "name": "Product Information", "blocks": [ { "type": "title", "name": "Title", "limit": 1 }, { "type": "price", "name": "Price", "limit": 1 }, { "type": "variant_picker", "name": "Variant picker", "limit": 1 }, { "type": "buy_buttons", "name": "Buy buttons", "limit": 1 }, { "type": "description", "name": "Description" }, { "type": "share", "name": "Share" }, { "type": "@app" } ]}{% endschema %}Cart Page
{# sections/main-cart.liquid #}
<div class="cart"> <div class="cart__items"> {# Cart items #} </div>
<div class="cart__footer"> {%- for block in section.blocks -%} {%- case block.type -%} {%- when 'subtotal' -%} <div {{ block.shopify_attributes }}> <span>Subtotal</span> <span>{{ cart.total_price | money }}</span> </div>
{%- when 'checkout_button' -%} <button type="submit" name="checkout" {{ block.shopify_attributes }}> Checkout </button>
{%- when '@app' -%} <div class="cart__app-block" {{ block.shopify_attributes }}> {% render block %} </div>
{%- endcase -%} {%- endfor -%} </div></div>
{% schema %}{ "name": "Cart", "blocks": [ { "type": "subtotal", "name": "Subtotal", "limit": 1 }, { "type": "checkout_button", "name": "Checkout button", "limit": 1 }, { "type": "@app" } ]}{% endschema %}App Embed Blocks
Some apps use embed blocks instead of section blocks. These appear in the theme editor under Theme settings → App embeds.
Embed blocks don’t require section changes. They inject content globally (like chat widgets, announcement bars, or analytics).
Difference from App Blocks
| App Blocks | App Embeds |
|---|---|
| Placed within sections | Global theme additions |
| Position controlled by merchant | Usually fixed position |
Require @app block type | No theme code needed |
| e.g., Reviews, wishlists | e.g., Chat, notifications |
Styling App Blocks
App blocks may not inherit your theme’s styles. Use defensive CSS:
/* Reset styles for app blocks */.product__app-block { margin: var(--spacing-md) 0;}
/* Let apps control their own content */.product__app-block > * { /* Avoid overriding app styles */}
/* But provide consistent container */.cart__app-block { padding: var(--spacing-sm) 0; border-top: 1px solid var(--color-border);}Testing App Compatibility
Without Installing Apps
Use placeholder blocks to simulate app blocks:
{%- when '@app' -%} <div class="app-block-placeholder" {{ block.shopify_attributes }}> {% render block %} </div>In development, you can create test blocks:
{ "blocks": { "app_1": { "type": "@app" } }}With Test Apps
- Install a free app that uses app blocks (e.g., Shopify Reviews)
- Add its blocks to your sections
- Verify styling and positioning
- Test removal and reinstallation
Theme App Extensions
App developers create Theme App Extensions that define:
- App blocks for sections
- App embed blocks
- App block settings
As a theme developer, you enable these by:
- Including
@appin relevant sections - Providing good default styling
- Testing with popular apps
Multiple @app Support
You can have multiple app blocks in a section:
{ "blocks": [ { "type": "title", "name": "Title" }, { "type": "@app" } ], "presets": [ { "name": "Product", "blocks": [ { "type": "title" } ] } ]}Merchants can add as many app blocks as needed.
App Block Positioning
Control where app blocks appear relative to other content:
{# Before product info #}{%- for block in section.blocks -%} {%- if block.type == '@app' and block.settings.position == 'before' -%} {% render block %} {%- endif -%}{%- endfor -%}
{# Product info #}<div class="product__main"> {%- for block in section.blocks -%} {%- unless block.type == '@app' -%} {# Render theme blocks #} {%- endunless -%} {%- endfor -%}</div>
{# After product info #}{%- for block in section.blocks -%} {%- if block.type == '@app' and block.settings.position != 'before' -%} {% render block %} {%- endif -%}{%- endfor -%}Or use settings:
{ "type": "@app"}Apps can define their own positioning preferences.
Recommended Sections for @app
Add @app support to these sections:
| Section | Common App Blocks |
|---|---|
| Product page | Reviews, wishlist, size guide |
| Collection page | Filters, quick view |
| Cart | Upsells, shipping calculator |
| Footer | Newsletter apps, trust badges |
| Product card | Quick add, wishlist button |
App Block Wrapper
Provide consistent containers:
{%- when '@app' -%} <div class="app-block app-block--{{ forloop.index }}" {{ block.shopify_attributes }} > {% render block %} </div>.app-block { /* Consistent spacing */ margin-block: var(--spacing-md);}
.app-block:empty { /* Hide if app renders nothing */ display: none;}Handling Missing Apps
When an app is uninstalled, its blocks remain in the JSON but render nothing:
{%- when '@app' -%} {# This safely renders nothing if app is gone #} {% render block %}No error handling needed; Shopify handles this gracefully.
Best Practices
Do
- Add
@appto all major sections - Provide wrapper elements with styling
- Test with popular apps
- Document app block locations
Don’t
- Override app styles aggressively
- Assume app content dimensions
- Require app blocks (make them optional)
- Break layout if app block is empty
Practice Exercise
Add app block support to:
- Product information section
- Cart section
- Footer section
Test by:
- Installing a reviews app
- Adding app blocks in theme editor
- Verifying layout doesn’t break
- Removing app and checking graceful fallback
Key Takeaways
@appblock type enables app blocks{% render block %}outputs app content- App embeds are global, no code needed
- Defensive styling prevents layout breaks
- Popular sections should support apps
- Graceful fallback when apps removed
- No special handling for missing apps
What’s Next?
The final lesson covers Upgrade-Safe Customization Patterns for maintainable theme modifications.
Finished this lesson?
Mark it complete to track your progress.
Discussion
Loading comments...