Getting Started

What is Adobe Edge Delivery Services?

Adobe Edge Delivery Services (EDS, formerly known as Franklin or Project Helix) is a document-based content management system that represents a paradigm shift in web development. Unlike traditional CMSs that require content authors to adapt to rigid structures, EDS flips this relationship—the system adapts to how authors naturally create content.

Content creators work in familiar tools like Google Docs or Microsoft Word, while the system handles the technical transformation into high-performance web pages. This separation of concerns allows content authors to focus on writing in familiar environments while developers build functionality without disrupting content workflows.

Key Features:

  • Document-based authoring (Google Docs, Microsoft Word)
  • Perfect Core Web Vitals scores (100/100/100/100)
  • No build process or compilation required
  • Vanilla JavaScript and pure CSS (no frameworks)
  • Automatic image optimization and responsive images
  • Sophisticated three-phase loading strategy (E-L-D)
How does EDS differ from traditional CMSs?

EDS takes a fundamentally different approach compared to traditional content management systems:

Traditional CMS:

  • Dedicated authoring and publishing environments
  • Custom interfaces authors must learn
  • Complex deployment pipelines and build processes
  • Framework dependencies (React, Vue, Angular)
  • Bundling and compilation required
  • Authors adapt to the system's structure

Edge Delivery Services:

  • Authors use Google Docs or Microsoft Word directly
  • No dedicated authoring environment needed
  • Zero build process or pipelines
  • Vanilla JavaScript and CSS only
  • Instant preview for every GitHub branch
  • System adapts to how authors naturally work
  • Content published directly to edge servers

This "content-first philosophy" means the technical implementation serves the content creation process, not the other way around.

What is the content-first philosophy?

At its core, EDS embraces a content-first approach that radically simplifies the authoring process. Content creators work in familiar tools like Google Docs or Microsoft Word, while the system handles the technical transformation into structured web pages.

This philosophy enables:

  • Authors focus on writing - No need to learn complex CMS interfaces
  • Developers build functionality - Without disrupting content workflows
  • Parallel workflows - Both teams work simultaneously, accelerating delivery
  • Natural content creation - Authors use tools they already know
  • Clean separation - Content and code evolve independently

As a developer working with EDS, understanding this philosophy is crucial—your job isn't to build a website from scratch, but to enhance how documents transform into web experiences.

How do I set up a new EDS project?

Setting up a new Edge Delivery Services project involves a few key steps:

  1. Create GitHub Repository - Use the Adobe Helix boilerplate template as your starting point
  2. Set up Content Source - Create a folder in Google Drive or SharePoint where content will live
  3. Configure fstab.yaml - Connect your GitHub repository to your content source
  4. Install Sidekick - Add the Adobe Sidekick browser extension for preview and publishing
  5. Create First Page - Add a Google Doc to your content folder and preview it

Key Requirements:

  • GitHub account for code repository
  • Google Drive or SharePoint for content storage
  • Chrome or Edge browser for Sidekick extension
  • Basic understanding of HTML, CSS, and JavaScript

Once set up, every branch in your GitHub repository gets its own preview URL (branch--repo--owner.aem.page), making collaboration and testing straightforward.

What is fstab.yaml and how does it work?

The fstab.yaml file is the critical configuration that connects your GitHub code repository to your content source (Google Drive or SharePoint). It defines "mountpoints" that map URL paths to content locations.

Basic Structure:

mountpoints:
  /: https://drive.google.com/drive/folders/[FOLDER_ID]

What it does:

  • Maps root URL path (/) to specific Google Drive folder
  • Tells EDS where to find content documents
  • Can map different paths to different folders
  • Enables content authors to work in Drive while developers work in GitHub

Key Points:

  • File must be in repository root
  • YAML format (whitespace-sensitive)
  • Folder must be shared with helix@adobe.com
  • Changes require commit to GitHub

This configuration is what enables the separation between code (GitHub) and content (Google Drive/SharePoint) that makes EDS unique.

What is the Adobe Sidekick browser extension?

The Adobe Sidekick is a browser extension that provides essential tools for content authors working with Edge Delivery Services. It bridges the gap between Google Docs and the live website.

Key Features:

  • Preview - See how your Google Doc will look as a web page before publishing
  • Publish - Push content live to production with one click
  • Unpublish - Remove content from production
  • Switch Environments - Toggle between dev, preview, and live URLs
  • Reload - Refresh preview to see latest changes
  • Config Activation - Activate .helix/config changes when published

How It Works:

  1. Install extension in Chrome or Edge browser
  2. Open any Google Doc in your configured Drive folder
  3. Sidekick toolbar appears in browser
  4. Click "Preview" to see page on .aem.page domain
  5. Click "Publish" to push to .aem.live and production

The Sidekick makes EDS accessible to non-technical content authors—they never need to touch GitHub or understand deployment pipelines.

How does the document transformation process work?

The document transformation is the heart of how EDS works. A Google Doc goes through five distinct stages before becoming a fully-functional web page:

Stage 1: Document Creation

  • Author creates content in Google Docs using headings, paragraphs, images, links
  • Tables define blocks like "Columns" or "Cards"
  • Horizontal rules (---) create section breaks
  • Metadata table defines page SEO properties

Stage 2: Document to Markdown (Server-Side)

  • EDS accesses document via Google Docs API
  • Converts document to Markdown format
  • Tables processed as potential blocks
  • Images extracted and stored separately

Stage 3: Markdown to Initial HTML (Server-Side)

  • Markdown converted to basic semantic HTML
  • Metadata applied to <head> section
  • Content divided into sections
  • Blocks identified with data-block-name attributes

Stage 4: Initial HTML Delivery (Browser)

  • Browser receives basic HTML
  • Core scripts (aem.js, scripts.js) load
  • DOM enhancement begins
  • Blocks decorated with CSS and JavaScript

Stage 5: Final DOM Transformation (Browser)

  • Images converted to responsive <picture> elements
  • Links enhanced to styled buttons
  • Sections wrapped with appropriate classes
  • Block-specific JavaScript executes

This multi-stage process allows content authors to focus on content while the system handles technical implementation.

Document Authoring

How do content authors create pages in EDS?

Content authors create pages in EDS using the same tools they already know: Google Docs or Microsoft Word. No special CMS training required.

Basic Content Elements:

  • Headings - H1 through H6 for structure
  • Paragraphs - Normal text with bold, italic, underline formatting
  • Lists - Bulleted or numbered lists
  • Images - Drag and drop images directly into document
  • Links - Standard hyperlinks to internal or external pages

EDS-Specific Features:

  • Section Breaks - Insert horizontal rule (---) to divide content into sections
  • Tables for Blocks - Create tables with block name in first cell to define components
  • Metadata Table - Special table with key-value pairs for SEO
  • Icon Syntax - Use :iconname: to insert SVG icons

Workflow:

  1. Create Google Doc in configured Drive folder
  2. Write content using standard formatting
  3. Click "Preview" in Sidekick to see web page
  4. Make changes and preview again (instant updates)
  5. Click "Publish" when ready to go live

Authors never touch code, GitHub, or command lines—they just write in Google Docs.

How do tables define blocks in documents?

Tables in Google Docs are the primary mechanism for creating blocks (components) in EDS. The first cell in the table tells EDS which block to create.

Basic Structure:

  • First cell contains block name (e.g., "Columns", "Cards", "Hero")
  • Remaining cells contain the block's content
  • Each row in the table typically represents a content item

Example - Simple Columns Block:

Table in Google Doc:

| Columns |
| Text in first column | Text in second column |

Becomes HTML:

<div class="columns">
  <div>
    <div>Text in first column</div>
    <div>Text in second column</div>
  </div>
</div>

Table-to-Div Transformation:

  • Table element removed from final HTML
  • Each table row becomes a <div>
  • Each table cell becomes a nested <div>
  • Block name becomes CSS class

This transformation allows authors to structure complex layouts using familiar table interfaces, while developers work with clean div-based HTML.

How do I create block variations?

Block variations allow authors to apply different styling or behavior to blocks without requiring separate block implementations. Simply add options in parentheses after the block name.

Syntax:

BlockName (variation1, variation2)

Example:

Table in Google Doc:

| Columns (dark, wide) |
| Content here | More content |

Becomes HTML:

<div class="columns dark wide">
  ...
</div>

How Developers Use Variations:

CSS handles styling differences:

.columns { display: grid; }
.columns.wide { max-width: 1200px; }
.columns.dark { background: #333; color: white; }

JavaScript can detect variations:

export default function decorate(block) {
  const isWide = block.classList.contains('wide');
  const isDark = block.classList.contains('dark');
  // Apply appropriate logic
}

Benefits:

  • Authors control appearance without code changes
  • One block codebase serves multiple use cases
  • Variations can be combined freely
  • No need to create separate block types
How do I add metadata to my pages?

Metadata in EDS is defined using a special table at the end of your Google Doc. This metadata becomes SEO tags, Open Graph properties, and other page-level configuration.

Structure:

  • Create a 2-column table at end of document
  • First row: merge cells and type "Metadata"
  • Subsequent rows: key in left cell, value in right cell

Common Metadata Keys:

  • Title - Page title (appears in browser tab and search results)
  • Description - Meta description for SEO
  • og:image - Social sharing image URL
  • og:title - Social sharing title
  • og:description - Social sharing description
  • author - Page author name
  • template - Custom page template
  • theme - Page theme name

Transformation:

Metadata table in Google Doc:

| Metadata |
| Title | My Page Title |
| Description | A great page |

Becomes HTML:

<title>My Page Title</title>
<meta name="description" content="A great page">
<meta property="og:title" content="My Page Title">

EDS automatically generates all appropriate meta tags from your metadata table.

What is a section and how do I create one?

Sections are logical divisions of content on a page. They allow you to apply different styling or layouts to different parts of the page.

Creating Sections:

  • Insert a horizontal rule (---) in your Google Doc
  • Content before the rule becomes one section
  • Content after the rule becomes the next section
  • Each section gets wrapped in a <div class="section">

Example:

Google Doc content:

# Heading 1
Some content here
---
# Heading 2
More content here

Becomes HTML:

<div class="section">
  <h1>Heading 1</h1>
  <p>Some content here</p>
</div>
<div class="section">
  <h1>Heading 2</h1>
  <p>More content here</p>
</div>

Why Use Sections:

  • Apply different background colors
  • Control layout and spacing
  • Enable/disable certain features per section
  • Create visual hierarchy on the page

The first section typically contains the hero or main heading, while subsequent sections contain body content.

How does the icon system work?

EDS provides an elegant system for incorporating SVG icons into content using a simple text syntax that authors can type directly.

Syntax:

:iconname:

Example:

In Google Doc: :training:

Becomes HTML: <span class="icon icon-training"></span>

Final rendering: <img src="https://yoursite.com/icons/training.svg" alt="Training icon">

How It Works:

  1. EDS identifies text between colons during transformation
  2. Creates a <span> with icon and icon-{name} classes
  3. Looks for matching SVG file in /icons/ directory
  4. Replaces span with <img> tag pointing to SVG

Developer Setup:

  • Create /icons/ directory at project root
  • Add SVG files named training.svg, warning.svg, etc.
  • Optimize SVGs for web (remove metadata)
  • Document available icons for authors

Benefits:

  • Authors use simple syntax (no HTML knowledge required)
  • Centralized icon management
  • Consistent implementation across site
  • Semantic HTML with accessibility attributes
How are images handled in documents?

EDS automatically transforms images from Google Docs into highly optimized, responsive images using modern web standards.

Author Experience:

  • Drag and drop images directly into Google Doc
  • No need to worry about file size or format
  • No manual optimization required

Automatic Transformation:

Simple image in document becomes:

<picture>
  <source type="image/webp" srcset="image.png?width=2000&format=webp" media="(min-width: 600px)">
  <source type="image/webp" srcset="image.png?width=750&format=webp">
  <source type="image/png" srcset="image.png?width=2000&format=png" media="(min-width: 600px)">
  <img loading="lazy" alt="Description" src="image.png?width=750" width="1600" height="400">
</picture>

Automatic Features:

  • Multiple Sizes - 750px for mobile, 2000px for desktop
  • WebP Format - Modern format with smaller file sizes
  • Fallbacks - PNG/JPEG for browsers without WebP
  • Responsive - Media queries select appropriate size
  • Lazy Loading - Images below fold load on demand
  • Eager Loading - Hero images load immediately
  • Dimensions - Width and height prevent layout shift

This sophisticated optimization happens automatically—authors just insert images, and EDS handles the rest.

What's the difference between preview and publish?

EDS provides two distinct environments for content: preview (for testing) and publish (for production).

Preview Environment:

  • URL: branch--repo--owner.aem.page
  • Purpose: Testing and review before going live
  • Updates: Instant—changes appear immediately
  • Access: Can be restricted to authorized users
  • SEO: Not indexed by search engines
  • Trigger: Click "Preview" button in Sidekick

Live/Published Environment:

  • URL: branch--repo--owner.aem.live or custom domain
  • Purpose: Production content for public
  • Updates: Requires explicit "Publish" action
  • Access: Public (unless authentication configured)
  • SEO: Indexed by search engines
  • Trigger: Click "Publish" button in Sidekick

Workflow:

  1. Author makes changes in Google Doc
  2. Click "Preview" to see changes instantly
  3. Review and make more changes if needed
  4. When satisfied, click "Publish" to push live
  5. Published content goes to CDN and production domain

This separation allows safe testing without affecting the live site.

Block Development

How do blocks work in EDS?

Blocks are the fundamental building units for custom functionality in EDS. They allow documents to include specialized components and layouts while maintaining the content-first philosophy.

How Blocks Are Created:

  • Authors create blocks using tables in Google Docs
  • First cell defines the block type (e.g., "Columns", "Cards")
  • Remaining cells contain block content
  • System transforms table to semantic HTML divs

Block File Structure:

Each block lives in its own directory:

/blocks/blockname/
  blockname.js   // Core functionality
  blockname.css  // Styling
  README.md     // Documentation
  example.md    // Usage examples

Basic Block Implementation:

export default function decorate(block) {
  // Transform the block DOM as needed
  // 'block' is a DOM element with class 'blockname'
}

EDS calls the decorate() function automatically when it encounters your block, passing the block's DOM element. Your code can then transform it as needed—adding interactivity, fetching data, or reorganizing content.

What is the table-to-div transformation?

One of the most important transformations in EDS involves how tables from Google Docs are converted into HTML div elements. Understanding this is crucial for block development.

Transformation Process:

  1. Author creates table in Google Doc
  2. EDS identifies and parses the table
  3. Table structure converted to nested divs
  4. Each row becomes a <div>
  5. Each cell becomes a nested <div>

Example:

Google Doc table:

| Block Name |
| Cell 1 | Cell 2 | Cell 3 |
| Cell 4 | Cell 5 | Cell 6 |

Becomes HTML:

<div class="block-name">
  <div>
    <div>Cell 1</div>
    <div>Cell 2</div>
    <div>Cell 3</div>
  </div>
  <div>
    <div>Cell 4</div>
    <div>Cell 5</div>
    <div>Cell 6</div>
  </div>
</div>

Working with Transformed Content:

export default function decorate(block) {
  const rows = block.children;
  for (let i = 0; i < rows.length; i++) {
    const cells = rows[i].children;
    // Process each cell
  }
}

How do I write JavaScript for blocks?

EDS blocks follow specific JavaScript patterns for consistency and maintainability.

Required Structure:

  1. Configuration Object - Define all constants at top
  2. Main decorate Function - Default export that transforms block
  3. Helper Functions - Utility functions below main function

Template:

// Configuration
const BLOCKNAME_CONFIG = {
  ERROR_MESSAGE: 'Error loading content',
  API_URL: '/data/content.json',
  THRESHOLD: 10,
};

// Main decoration function
export default async function decorate(block) {
  try {
    // Clear initial content
    block.textContent = '';
    
    // Fetch data if needed
    const data = await fetchData();
    
    // Build content
    const content = buildContent(data);
    block.appendChild(content);
  } catch (error) {
    block.textContent = BLOCKNAME_CONFIG.ERROR_MESSAGE;
  }
}

// Helper functions
async function fetchData() {
  const response = await fetch(BLOCKNAME_CONFIG.API_URL);
  return response.json();
}

Key Principles:

  • Use async/await (never .then())
  • Include error handling with try/catch
  • No inline CSS—use CSS files
  • Use vanilla JavaScript—no frameworks
  • Keep imports minimal
How do CSS variations work for blocks?

CSS variations provide a powerful way to create multiple visual styles for a single block without writing separate implementations.

How Variations Are Applied:

When authors write BlockName (dark, wide) in Google Docs, EDS adds those as CSS classes:

<div class="blockname dark wide">

CSS Structure:

/* Base styles */
.columns {
  display: grid;
  gap: 20px;
}

/* Variation: wide */
.columns.wide {
  max-width: 1200px;
}

/* Variation: dark */
.columns.dark {
  background-color: #333;
  color: white;
}

/* Combined variations */
.columns.dark.wide {
  border: 1px solid #555;
}

JavaScript Detection:

export default function decorate(block) {
  const isDark = block.classList.contains('dark');
  const isWide = block.classList.contains('wide');
  
  if (isDark) {
    // Apply dark-specific logic
  }
}

Benefits:

  • One codebase for multiple styles
  • Authors control appearance
  • Variations can be combined freely
  • No code changes needed for new variations
What files are required for a block?

Each EDS block follows a standard file structure for consistency and maintainability.

Required Files:

/blocks/blockname/
├── blockname.js      // Core functionality (REQUIRED)
├── blockname.css     // Styling (REQUIRED)
├── README.md         // Documentation (REQUIRED)
└── example.md        // Usage examples (REQUIRED)

Optional Files:

├── demo.md           // Live demo content
├── example.json      // Sample data
└── example.csv       // CSV version of data

File Purposes:

  • blockname.js - Contains decorate() function and logic
  • blockname.css - Block-specific styling with CSS variables
  • README.md - Technical documentation for developers
  • example.md - Simple examples for content authors
  • demo.md - Comprehensive real-world usage
  • example.json/csv - Sample data files for testing

Critical Rules:

  • Exactly ONE JavaScript file per block (no variations)
  • Exactly ONE CSS file per block
  • File names must match directory name
  • All files lowercase with hyphens (kebab-case)
How do autoblocks work (hero, buttons)?

Autoblocking is EDS's system for automatically applying styling and structure to common content patterns without requiring authors to create explicit blocks.

How Autoblocking Works:

  1. System recognizes common content patterns
  2. Automatically transforms them into blocks
  3. Applies consistent styling without author intervention

Common Autoblocks:

1. Hero Block

  • Pattern: Image followed by heading at document start
  • Result: Automatically creates hero block
  • No table needed: EDS detects the pattern

2. Button Enhancement

  • Pattern: Links in standalone paragraphs
  • Result: Converted to styled buttons
  • Classes added: button, primary, button-container

Implementation in scripts.js:

function buildAutoBlocks(main) {
  const h1 = main.querySelector('h1');
  const picture = main.querySelector('picture');
  
  // If picture precedes h1, create hero
  if (h1 && picture &&
      picture.compareDocumentPosition(h1) === 4) {
    const section = document.createElement('div');
    section.append(buildBlock('hero',
      { elems: [picture, h1] }));
    main.prepend(section);
  }
}

Benefits:

  • Authors write naturally without learning block syntax
  • Consistent styling across site
  • Rich web experience with minimal table usage
  • Reduces content creation friction

Performance & Loading

What is the E-L-D (Eager-Lazy-Delayed) loading strategy?

E-L-D (Eager-Lazy-Delayed) is EDS's sophisticated three-phase loading strategy that's key to achieving perfect Core Web Vitals scores (100/100/100/100).

Phase E (Eager):

  • Purpose: Load critical content for Largest Contentful Paint (LCP)
  • Timeline: Begins immediately on page load
  • Components: First section (typically hero), main heading, hero image, critical CSS (styles.css), core scripts (aem.js, scripts.js)
  • Target: Keep payload before LCP below 100KB

Phase L (Lazy):

  • Purpose: Load important but non-critical elements
  • Timeline: After first section loads
  • Components: Remaining sections, header and footer, non-critical CSS (lazy-styles.css), below-the-fold images, additional fonts

Phase D (Delayed):

  • Purpose: Handle lowest-priority elements
  • Timeline: After 3-second delay
  • Components: Analytics, third-party scripts, marketing tools, social widgets, chat functionality, anything in delayed.js

Implementation:

// In scripts.js
async function loadEager(doc) {
  // Load first section only
  await loadSection(main.querySelector('.section'));
}

async function loadLazy(doc) {
  // Load remaining sections
  await loadSections(main);
}

function loadDelayed() {
  // 3-second delay before loading
  setTimeout(() => import('./delayed.js'), 3000);
}

This phased approach ensures critical content loads quickly while deferring less important resources.

How does EDS achieve perfect Lighthouse scores?

EDS consistently achieves perfect Lighthouse scores (100/100/100/100) through deliberate architectural choices and optimization strategies.

Key Strategies:

1. No Build Process

  • Vanilla JavaScript—no framework overhead
  • Pure CSS—no preprocessing
  • No bundling or compilation delays
  • Smaller file sizes

2. E-L-D Loading Pattern

  • Critical content loads first (Eager)
  • Below-fold content loads after (Lazy)
  • Analytics delayed 3+ seconds (Delayed)
  • Optimizes LCP and FID metrics

3. Automatic Image Optimization

  • Multiple sizes generated (750px, 2000px)
  • WebP format with fallbacks
  • Responsive picture elements
  • Lazy loading below fold
  • Eager loading for hero images

4. Minimal JavaScript Execution

  • Only load JS needed for visible content
  • Blocks load on-demand
  • No large framework parsing
  • Efficient DOM manipulation

5. CSS Optimization

  • Critical CSS inline in HTML head
  • Non-critical CSS lazy loaded
  • No unused CSS
  • CSS variables for theming

6. Edge Delivery

  • Content served from CDN edge locations
  • Minimal server processing
  • Fast TTFB (Time to First Byte)

Result: Consistent 100s across Performance, Accessibility, Best Practices, and SEO.

How are images automatically optimized?

EDS performs sophisticated automatic image optimization using the createOptimizedPicture() function from aem.js.

Transformation Example:

Simple image reference:

<img src="./image.png" alt="Description">

Becomes optimized responsive image:

<picture>
  <source type="image/webp"
    srcset="image.png?width=2000&format=webp"
    media="(min-width: 600px)">
  <source type="image/webp"
    srcset="image.png?width=750&format=webp">
  <source type="image/png"
    srcset="image.png?width=2000&format=png"
    media="(min-width: 600px)">
  <img loading="lazy"
    alt="Description"
    src="image.png?width=750&format=png"
    width="1600" height="400">
</picture>

Automatic Features:

  • Multiple Sizes - 750px (mobile), 2000px (desktop)
  • Format Optimization - WebP with PNG/JPEG fallback
  • Responsive Selection - Browser picks appropriate size
  • Lazy Loading - Below-fold images load on scroll
  • Eager Loading - Hero images load immediately
  • Dimensions - Width/height prevent layout shift (CLS)
  • Query Parameters - Size and format in URL

Loading Strategy:

// Hero images
<img loading="eager" ...>

// Below-fold images
<img loading="lazy" ...>

This optimization happens automatically—authors just insert images, and EDS handles performance.

What are Core Web Vitals and why do they matter?

Core Web Vitals are Google's metrics for measuring user experience on web pages. EDS is architected to excel at all three metrics.

The Three Metrics:

1. LCP (Largest Contentful Paint)

  • Measures: Time until largest content element renders
  • Good: Under 2.5 seconds
  • EDS Strategy: Eager loading of first section and hero image

2. FID (First Input Delay) / INP (Interaction to Next Paint)

  • Measures: Time from user interaction to browser response
  • Good: Under 100ms (FID) or 200ms (INP)
  • EDS Strategy: Minimal JavaScript execution, no framework overhead

3. CLS (Cumulative Layout Shift)

  • Measures: Visual stability during page load
  • Good: Under 0.1
  • EDS Strategy: Image dimensions set, no late-loading elements that push content

Why They Matter:

  • SEO: Google uses Core Web Vitals as ranking factors
  • User Experience: Faster sites have higher engagement
  • Conversion: Better performance = more conversions
  • Accessibility: Fast sites benefit all users, especially those on slow connections

EDS Advantage:

EDS sites consistently achieve 100/100/100/100 Lighthouse scores across all categories because the architecture prioritizes performance from the ground up.

How does lazy loading work in EDS?

Lazy loading in EDS applies to both content sections and images, ensuring optimal performance by loading resources only when needed.

Section Lazy Loading:

  1. Eager Phase - First section loads immediately
  2. Lazy Phase - Remaining sections load after first section completes
  3. On-Demand - Blocks within sections load as they're encountered

Image Lazy Loading:

// Above-the-fold (hero)
<img loading="eager" src="hero.jpg">

// Below-the-fold
<img loading="lazy" src="content.jpg">

Implementation in scripts.js:

async function loadLazy(doc) {
  const main = doc.querySelector('main');
  
  // Load all remaining sections
  await loadSections(main);
  
  // Load header and footer
  loadHeader(doc.querySelector('header'));
  loadFooter(doc.querySelector('footer'));
  
  // Load non-critical CSS
  loadCSS('/styles/lazy-styles.css');
}

Benefits:

  • Faster Initial Load - Only critical content loads first
  • Better LCP - Largest content paints quickly
  • Reduced Data Usage - Below-fold content may never load if user doesn't scroll
  • Improved TTI - Page becomes interactive faster

Native Browser Support:

EDS uses native loading="lazy" attribute—no custom JavaScript intersection observers needed for images.

Configuration & Deployment

What is .helix/config and why is it important?

The .helix/config file is the central configuration for EDS projects, controlling CDN integration, push invalidation, and environment setup.

What it controls:

  • CDN integration and routing
  • Push invalidation setup
  • Environment hostnames (preview, live, production)
  • Custom domain configuration
  • Access control and permissions

Format:

Two-column table with key and value columns (stored as spreadsheet).

Essential Keys:

name = Project Name
host = yourdomain.com
cdn.prod.type = cloudflare
cdn.prod.host = yourdomain.com
cdn.preview.host = main--repo--owner.aem.page
cdn.live.host = main--repo--owner.aem.live

Why it matters:

  • Without it: Custom domains won't work, cache won't clear on publish, environments won't be separated
  • With it: Seamless custom domain setup, automatic cache clearing, proper environment isolation

Activation:

  1. Create/edit .helix/config spreadsheet
  2. Publish the config file using Sidekick
  3. Changes take effect within 1-2 minutes

This configuration is crucial for production deployments with custom domains.

How do I configure a custom domain (CDN)?

Setting up a custom domain with EDS involves configuring your CDN (typically Cloudflare) to proxy requests to Adobe's EDS infrastructure.

Setup Steps:

  1. Add Domain to CDN - Sign up for Cloudflare (or other CDN) and add your domain
  2. Update DNS - Point your domain to CDN nameservers
  3. Configure .helix/config:

    cdn.prod.type = cloudflare
    cdn.prod.host = yourdomain.com
    cdn.prod.route = /
    cdn.live.host = main--repo--owner.aem.live

  4. Set up CDN Worker - Configure worker to proxy to EDS:

    // Cloudflare Worker
    const EDS_HOST = 'main--repo--owner.aem.live';

    async function handleRequest(request) {
      const url = new URL(request.url);
      url.hostname = EDS_HOST;
      return fetch(url, request);
    }

  5. Publish Config - Use Sidekick to activate configuration

Architecture:

Visitor
  ↓
Custom Domain (yourdomain.com)
  ↓
CDN (Cloudflare)
  ↓
EDS Live (.aem.live)
  ↓
Content Delivered

Benefits:

  • Branded domain for your site
  • CDN caching at edge locations
  • DDoS protection and security
  • Custom SSL certificates
What is push invalidation?

Push invalidation is the automatic cache clearing that happens when you publish content through the Sidekick. It ensures visitors see fresh content immediately.

How It Works:

  1. Author clicks "Publish" in Sidekick
  2. EDS publishes content to .aem.live
  3. EDS calls CDN API to purge cache
  4. CDN clears cached content
  5. Next visitor gets fresh content
  6. Content re-caches automatically

Configuration Required:

In .helix/config:

cloudflare.apiToken = [your-api-token]
cloudflare.zoneId = [your-zone-id]

Without Push Invalidation:

  • Published changes don't appear until cache expires
  • Manual "Purge Everything" required after each publish
  • Visitors see stale content
  • Frustrating authoring experience

With Push Invalidation:

  • Changes appear within 5-10 seconds
  • Seamless publishing workflow
  • Authors see results immediately
  • No manual cache clearing needed

Security:

  • API token has minimum permissions (Cache Purge only)
  • Token scoped to specific zone
  • Rotate token annually

Push invalidation is essential for production sites with custom domains and CDN caching.

How do preview, live, and production environments work?

EDS provides three distinct environments for different stages of the content lifecycle.

Environment Hierarchy:

1. Preview Environment (.aem.page)

  • URL: main--repo--owner.aem.page
  • Purpose: Draft content testing
  • Updates: Instant (no publish needed)
  • Access: Can be restricted to editors
  • SEO: Not indexed
  • Use Case: Authors preview changes before publishing

2. Live Environment (.aem.live)

  • URL: main--repo--owner.aem.live
  • Purpose: Published content on Adobe CDN
  • Updates: Requires "Publish" action
  • Access: Public (unless restricted)
  • SEO: Indexed if not proxied
  • Use Case: Source for production domain

3. Production Environment (Custom Domain)

  • URL: yourdomain.com
  • Purpose: Public-facing site
  • Updates: Via publish + push invalidation
  • Access: Public
  • SEO: Primary indexed domain
  • Use Case: What visitors see

Content Flow:

Edit in Google Docs
  ↓ Preview
Preview (.aem.page) - instant
  ↓ Publish
Live (.aem.live) - published
  ↓ CDN Proxy
Production (yourdomain.com) - cached

This separation enables safe testing without affecting the live site.

What is the double CDN architecture?

EDS often uses a "double CDN" architecture where a customer's CDN (like Cloudflare) sits in front of Adobe's Fastly CDN.

Architecture Flow:

Visitor
  ↓
Cloudflare CDN (Your CDN)
  ↓
Cloudflare Worker
  ↓
Adobe Fastly CDN (EDS CDN)
  ↓
Adobe EDS Origin
  ↓
Content Delivered

Why Double CDN?

Layer 1: Your CDN (Cloudflare)

  • Purpose: Primary edge caching and security
  • Benefits: DDoS protection, Web Application Firewall, custom SSL, analytics, cache control, 300+ edge locations

Layer 2: Adobe CDN (Fastly)

  • Purpose: EDS-specific optimizations
  • Benefits: Image optimization, content transformation, EDS platform features

How It Works:

  1. Visitor requests yourdomain.com/page
  2. Cloudflare checks its cache
  3. If miss, Cloudflare Worker proxies to .aem.live
  4. Adobe Fastly processes request
  5. Content returned to Cloudflare
  6. Cloudflare caches and serves to visitor

Performance Impact:

  • First request: Two CDN hops (slower)
  • Subsequent requests: Served from Cloudflare edge (fast)
  • Cache hit rates typically 95%+

Benefits:

  • You control security and caching
  • Cloudflare Free plan provides unlimited bandwidth
  • Adobe handles EDS-specific optimizations
  • Best of both platforms
How do I publish changes with the Sidekick?

Publishing with the Adobe Sidekick is the primary way content authors push changes from draft to production.

Publishing Workflow:

  1. Edit Content - Make changes in Google Doc
  2. Preview - Click "Preview" in Sidekick to see draft
  3. Review - Check content on .aem.page URL
  4. Iterate - Make more edits if needed (instant preview updates)
  5. Publish - Click "Publish" button when ready
  6. Verify - Check production domain

What Happens on Publish:

  1. Content pushed to .aem.live URL
  2. If push invalidation configured, CDN cache cleared
  3. Production domain serves fresh content within 5-10 seconds
  4. Content re-caches on next request

Sidekick Buttons:

  • Preview - View draft on .aem.page
  • Publish - Push to .aem.live and production
  • Unpublish - Remove from production (keeps preview)
  • Reload - Refresh preview after edits
  • Edit - Return to Google Doc

Bulk Publishing:

  • Sidekick supports bulk operations
  • Publish multiple pages at once
  • Useful for site-wide updates

Code Publishing:

For code changes (JavaScript, CSS):

  1. Commit to GitHub
  2. Changes automatically deploy to preview
  3. Use Sidekick on any page to activate for production

The Sidekick makes publishing accessible to non-technical authors.

Data & Content Management

What is query-index.json?

query-index.json is a powerful EDS feature that provides automatic indexing of all content in a folder, enabling dynamic content access.

What It Is:

  • Automatically generated JSON file
  • Available in every Google Drive folder
  • Contains metadata about all published pages
  • Updates automatically when content published

Setup:

  1. Create blank spreadsheet named query-index in Drive folder
  2. Publish pages in that folder
  3. EDS automatically populates spreadsheet with page metadata
  4. Access via /folder-path/query-index.json

Data Structure:

{
  "total": 25,
  "offset": 0,
  "limit": 25,
  "data": [
    {
      "path": "/blogs/article-1",
      "title": "Article Title",
      "image": "/media/image.jpg",
      "description": "Article summary",
      "lastModified": "1640000000"
    }
  ]
}

Use Cases:

  • Blog Listings - Dynamic list of blog posts
  • Navigation Menus - Auto-generated from content
  • Related Content - Show similar articles
  • Search - Client-side search of all content
  • Feeds - RSS/Atom generation

Example Usage:

async function loadBlogList() {
  const response = await fetch('/blogs/query-index.json');
  const data = await response.json();
  
  data.data.forEach(post => {
    // Render blog post card
  });
}

This enables dynamic functionality without databases or APIs.

How do I use spreadsheets with EDS?

Spreadsheets in EDS serve multiple purposes: as data sources, configuration files, and automatic indexing.

Spreadsheet Types:

1. Data Sources

  • Create spreadsheet in Google Drive folder
  • EDS converts to JSON automatically
  • Access via /path/spreadsheet-name.json
  • Use for product catalogs, team listings, etc.

2. Configuration Sheets

  • headers - Site header navigation
  • footers - Site footer content
  • redirects - URL redirect rules
  • .helix/config - Site configuration

3. Auto-Generated Sheets

  • query-index - Page metadata index
  • Populated automatically by EDS
  • Updates when pages published

Example - Product List:

Spreadsheet products.xlsx:

| name | price | image |
| Widget | $19.99 | /images/widget.jpg |
| Gadget | $29.99 | /images/gadget.jpg |

Becomes /products.json:

{
  "data": [
    {
      "name": "Widget",
      "price": "$19.99",
      "image": "/images/widget.jpg"
    }
  ]
}

Usage in Blocks:

async function decorate(block) {
  const response = await fetch('/products.json');
  const { data } = await response.json();
  
  data.forEach(product => {
    // Render product card
  });
}

Spreadsheets provide a simple way for non-technical users to manage structured data.

How do I set up URL redirects?

URL redirects in EDS are managed through a simple spreadsheet named redirects.

Setup:

  1. Create spreadsheet named redirects in Google Drive root
  2. Add two columns: Source and Destination
  3. Publish the spreadsheet
  4. EDS generates /redirects.json

Spreadsheet Format:

| Source | Destination |
| /old-page | /new-page |
| /blog/2023/post | /blog/2024/post |
| /products/* | /shop/* |

Redirect Types:

  • Exact Match: /old-page/new-page
  • Wildcard: /old/*/new/*
  • External: /linkhttps://external.com

Generated JSON:

{
  "data": [
    {
      "source": "/old-page",
      "destination": "/new-page"
    }
  ]
}

How It Works:

  1. User requests old URL
  2. EDS checks redirects.json
  3. If match found, returns 301 redirect
  4. Browser navigates to new URL

Best Practices:

  • Use 301 (permanent) redirects for moved content
  • Keep redirect list under 1000 entries
  • Test redirects after publishing
  • Document why each redirect exists

This spreadsheet-based approach makes redirect management accessible to content editors.

What core JavaScript files does EDS use?

EDS relies on three core JavaScript files that orchestrate page loading and enhancement.

1. aem.js (formerly lib-franklin.js)

  • Purpose: Foundation utility functions
  • Key Functions:
    • toClassName() - Convert text to CSS class
    • readBlockConfig() - Extract block configuration
    • loadCSS() - Load stylesheets dynamically
    • getMetadata() - Access page metadata
    • createOptimizedPicture() - Generate responsive images
    • decorateButtons() - Enhance links to buttons
    • loadBlock() - Load and decorate blocks
  • DO NOT MODIFY: This file should never be edited

2. scripts.js

  • Purpose: Orchestrates three-phase loading (E-L-D)
  • Key Functions:
    • buildAutoBlocks() - Create autoblocks (hero, buttons)
    • loadEager() - Load critical first section
    • loadLazy() - Load remaining sections
    • loadDelayed() - Load analytics after 3s delay
  • Customizable: Can add project-specific logic

3. delayed.js

  • Purpose: Non-critical functionality after 3-second delay
  • Common Uses:
    • Analytics (Google Analytics, Adobe Analytics)
    • Cookie consent banners
    • Marketing pixels
    • Chat widgets
    • Third-party scripts
  • Initially Empty: Add custom delayed functionality here

Load Order:

  1. aem.js - Loaded in <head>
  2. scripts.js - Loaded in <head>
  3. Page renders, first section loads (Eager)
  4. Remaining sections load (Lazy)
  5. After 3 seconds, delayed.js imports

These three files form the backbone of EDS's performance-optimized architecture.

How does GitHub integrate with EDS?

GitHub serves as the code repository for EDS projects, providing version control, collaboration, and automatic deployment.

What Lives in GitHub:

  • JavaScript files (scripts.js, aem.js, block code)
  • CSS files (styles.css, block styles)
  • Configuration (fstab.yaml, .helix/)
  • Default JSON files (fallback data)
  • Documentation and README files

What Lives in Google Drive:

  • Content documents (pages written in Google Docs)
  • Images and media assets
  • Spreadsheets (data, configuration)
  • Author-managed content

Branch-Based Previews:

Every GitHub branch gets its own preview URL:

  • mainmain--repo--owner.aem.page
  • featurefeature--repo--owner.aem.page
  • devdev--repo--owner.aem.page

Deployment Flow:

  1. Developer pushes code to GitHub branch
  2. EDS automatically deploys to that branch's preview URL
  3. Test changes on branch--repo--owner.aem.page
  4. Merge to main when ready
  5. Production uses main branch code

Fallback Pattern:

Create matching JSON files in GitHub for developer-managed defaults. Authors can override by creating spreadsheets in Google Drive.

Example:

  • Create /data/products.json in GitHub (default)
  • Authors can create products.xlsx in Drive (override)
  • Drive version takes precedence when published

This separation enables parallel workflows: developers code in GitHub while authors write in Google Docs.

Advanced Topics

How do I debug EDS applications?

Debugging EDS applications involves understanding the transformation process and using browser developer tools effectively.

Essential Debugging Techniques:

1. Compare Raw vs Processed HTML

  • View raw HTML: Add .plain.html to URL
  • Example: /page.plain.html shows server output before JavaScript
  • Compare with final DOM in DevTools

2. Inspect Network Requests

  • Open Network tab in DevTools
  • Check which CSS and JS files load
  • Verify blocks load their assets
  • Look for 404s or failed requests

3. Add Debug Logging

// In block code
// eslint-disable-next-line no-console
console.log('Block data:', data);

// In scripts.js
// eslint-disable-next-line no-console
console.log('Loading block:', blockName);

4. Use DOM Breakpoints

  • Right-click element in DevTools
  • Select "Break on" → "Subtree modifications"
  • See exactly when DOM changes occur

5. Check Block Loading

// See which blocks are loading
document.querySelectorAll('[data-block-status]')

6. Inspect CSS Application

  • Use Computed tab in DevTools
  • See which CSS rules apply
  • Check for specificity issues
  • Verify CSS file loaded

7. Test Without Cache

  • Hard refresh: Ctrl+Shift+R (Windows) or Cmd+Shift+R (Mac)
  • Or disable cache in DevTools Network tab

Common Issues:

  • Block not appearing: Check block name matches file name
  • Styles not applying: Verify CSS file name matches block
  • JavaScript errors: Check browser console for errors
  • Content not updating: Clear CDN cache or hard refresh
What development requirements does EDS have?

EDS has specific development requirements designed to maximize simplicity, performance, and maintainability.

Language Requirements:

JavaScript

  • ✅ Modern JavaScript (ES6+)
  • ✅ Vanilla JS only—no frameworks
  • ✅ ES modules with import/export
  • ✅ Async/await (never .then())
  • ❌ No TypeScript
  • ❌ No React, Vue, Angular, etc.
  • ❌ No JSX
  • ❌ No transpilation

CSS

  • ✅ Pure CSS3
  • ✅ CSS variables for theming
  • ✅ Modern features (Grid, Flexbox)
  • ❌ No preprocessors (Sass, Less, Stylus)
  • ❌ No CSS-in-JS
  • ❌ No inline styles in JavaScript

Build Process:

  • ❌ No build step required
  • ❌ No bundling (Webpack, Rollup, etc.)
  • ❌ No compilation
  • ✅ Files served directly as written
  • ✅ Optional: /build/ directory for complex components

Code Organization:

  • Configuration constants at top of files
  • Single JavaScript file per block
  • Single CSS file per block
  • Descriptive function names
  • Clear comments explaining "why"

Why These Requirements?

  • Performance: No framework overhead, smaller files
  • Simplicity: No toolchain complexity
  • Maintainability: Standard JavaScript anyone can read
  • Speed: No build time, instant deployment
  • Core Web Vitals: Achieves perfect Lighthouse scores

These constraints are deliberate design choices that prioritize performance and simplicity over developer convenience.

How do responsive images work (picture elements)?

EDS uses HTML5 <picture> elements to create responsive images that adapt to device capabilities and screen sizes.

Picture Element Structure:

<picture>
  <source type="image/webp"
    srcset="image.png?width=2000&format=webp"
    media="(min-width: 600px)">
  <source type="image/webp"
    srcset="image.png?width=750&format=webp">
  <source type="image/png"
    srcset="image.png?width=2000&format=png"
    media="(min-width: 600px)">
  <img loading="lazy"
    src="image.png?width=750&format=png"
    alt="Description"
    width="1600" height="400">
</picture>

How Browser Selects Image:

  1. Check Media Queries - Is screen >= 600px?
  2. Check Format Support - Does browser support WebP?
  3. Select Best Match:
    • Desktop + WebP support → 2000px WebP
    • Mobile + WebP support → 750px WebP
    • Desktop + No WebP → 2000px PNG
    • Mobile + No WebP → 750px PNG

Query Parameters:

  • width=750 - Resize to 750px wide
  • format=webp - Convert to WebP format
  • optimize=medium - Balance quality/size

Benefits:

  • Automatic Sizing - Browser picks appropriate size
  • Format Selection - WebP when supported, fallback otherwise
  • Bandwidth Savings - Mobile gets smaller images
  • Performance - Optimal image for each device
  • No JavaScript - Native browser feature

Generated by:

// In aem.js
createOptimizedPicture(src, alt, eager, breakpoints)

EDS handles all this automatically—authors just insert images.

What is Content-Driven Development (CDD)?

Content-Driven Development (CDD) is an EDS methodology that prioritizes content structure and author experience before implementing technical functionality.

CDD Process:

  1. Content Model First
    • Design how authors will create content
    • Define table structure for blocks
    • Consider author mental model
    • Keep it simple and intuitive
  2. Create Test Content
    • Authors create example content in Google Docs
    • Validate content model is author-friendly
    • Adjust model based on feedback
  3. Implement Functionality
    • Write JavaScript to transform content
    • Add CSS for styling
    • Test with real content examples
  4. Document and Iterate
    • Create example.md with usage
    • Write README.md with details
    • Gather author feedback
    • Refine based on usage

Example - Hero Block:

Bad (Code-First):

// Complex table structure
| Hero | image | title | subtitle | cta-text | cta-url |
| ... complicated for authors

Good (Content-First):

// Natural for authors - just image + heading
[Image]
# Page Title

EDS auto-creates hero block—no table needed!

CDD Principles:

  • Author Needs First - Optimize for content creators
  • Natural Content - Use familiar document patterns
  • Avoid Complexity - Simpler content models win
  • Test Early - Validate with real authors
  • Iterate - Refine based on usage

Benefits:

  • Better author experience
  • Fewer authoring errors
  • Faster content creation
  • More maintainable blocks
  • Reduced training needs

CDD ensures technical implementation serves content creation, not the other way around.