> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/angular/angular/llms.txt
> Use this file to discover all available pages before exploring further.

# Hydration

> Optimize Angular SSR applications with hydration for seamless client-side takeover

## Overview

Hydration is the process of attaching Angular's client-side JavaScript to server-rendered HTML, making the application interactive without re-rendering the entire page. This provides the best of both worlds: fast initial page load from SSR and full interactivity from the client-side application.

## Why Hydration?

Without hydration, Angular would destroy the server-rendered DOM and re-render everything on the client, causing:

* Visible content flash
* Lost user interactions during transition
* Wasted rendering work
* Poor user experience

<CardGroup cols={2}>
  <Card title="No Content Flash" icon="eye">
    Server-rendered content stays visible during client bootstrap.
  </Card>

  <Card title="Faster Interactivity" icon="bolt">
    Application becomes interactive faster by reusing existing DOM.
  </Card>

  <Card title="Better Performance" icon="gauge-high">
    Avoids duplicate rendering work on the client.
  </Card>

  <Card title="Improved Core Web Vitals" icon="chart-line">
    Better LCP (Largest Contentful Paint) and CLS (Cumulative Layout Shift) scores.
  </Card>
</CardGroup>

## Enabling Hydration

### Client Configuration

Add `provideClientHydration()` to your application configuration.

```typescript theme={null}
// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { provideClientHydration } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, {
  providers: [
    provideClientHydration()
  ]
}).catch(err => console.error(err));
```

### Server Configuration

No additional configuration needed on the server. Hydration metadata is automatically added during SSR.

```typescript theme={null}
// app.config.server.ts
import { ApplicationConfig, mergeApplicationConfig } from '@angular/core';
import { provideServerRendering } from '@angular/platform-server';
import { appConfig } from './app.config';

const serverConfig: ApplicationConfig = {
  providers: [
    provideServerRendering()
  ]
};

export const config = mergeApplicationConfig(appConfig, serverConfig);
```

## How Hydration Works

Angular's hydration process involves several steps:

1. **Server Rendering**: Angular renders the application on the server and adds special hydration markers (comments) to the HTML
2. **Client Bootstrap**: Angular bootstraps on the client and locates hydration markers
3. **DOM Reuse**: Angular attaches to existing DOM nodes instead of creating new ones
4. **Event Replay**: User interactions during hydration are captured and replayed
5. **Full Interactivity**: Application becomes fully interactive

```html theme={null}
<!-- Server-rendered HTML with hydration markers -->
<app-root>
  <!--ngh="0"-->
  <div>
    <h1>Welcome</h1>
    <!--ngh="1"-->
    <p>Server-rendered content</p>
    <!--/ngh-->
  </div>
  <!--/ngh-->
</app-root>
```

## Advanced Features

### I18n Support

Enable hydration support for internationalized applications.

```typescript theme={null}
import { bootstrapApplication } from '@angular/platform-browser';
import { 
  provideClientHydration, 
  withI18nSupport 
} from '@angular/platform-browser';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, {
  providers: [
    provideClientHydration(
      withI18nSupport()
    )
  ]
});
```

### Event Replay

Capture and replay user interactions that occur during hydration.

```typescript theme={null}
import { bootstrapApplication } from '@angular/platform-browser';
import { 
  provideClientHydration, 
  withEventReplay 
} from '@angular/platform-browser';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, {
  providers: [
    provideClientHydration(
      withEventReplay()
    )
  ]
});
```

<Note>
  Event replay ensures that user clicks and interactions during the hydration process are not lost and are executed once the application is fully interactive.
</Note>

### Incremental Hydration

Hydrate components on-demand for better performance with large applications.

```typescript theme={null}
import { bootstrapApplication } from '@angular/platform-browser';
import { 
  provideClientHydration, 
  withIncrementalHydration 
} from '@angular/platform-browser';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, {
  providers: [
    provideClientHydration(
      withIncrementalHydration()
    )
  ]
});
```

## Hydration-Compatible Code

### Direct DOM Manipulation

Avoid direct DOM manipulation that conflicts with hydration.

```typescript theme={null}
// ❌ Bad: Direct DOM manipulation
import { Component, ElementRef, AfterViewInit } from '@angular/core';

@Component({
  selector: 'app-bad',
  template: `<div #container></div>`
})
export class BadComponent implements AfterViewInit {
  constructor(private elementRef: ElementRef) {}

  ngAfterViewInit(): void {
    // This conflicts with hydration
    this.elementRef.nativeElement.innerHTML = '<p>Dynamic content</p>';
  }
}

// ✅ Good: Use Angular templating
import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-good',
  template: `
    <div>
      <p *ngIf="showContent()">Dynamic content</p>
    </div>
  `
})
export class GoodComponent {
  showContent = signal(false);

  ngAfterViewInit(): void {
    this.showContent.set(true);
  }
}
```

### Skip Hydration

Skip hydration for specific components when necessary.

```typescript theme={null}
import { Component } from '@angular/core';
import { NgComponentOutlet } from '@angular/common';

@Component({
  selector: 'app-dynamic',
  template: `
    <!-- Skip hydration for this component -->
    <div ngSkipHydration>
      <third-party-component></third-party-component>
    </div>
  `
})
export class DynamicComponent {}
```

### Handle Browser-Only Features

Ensure code works correctly during both SSR and hydration.

```typescript theme={null}
import { 
  Component, 
  OnInit, 
  PLATFORM_ID, 
  Inject,
  signal 
} from '@angular/core';
import { isPlatformBrowser } from '@angular/common';

@Component({
  selector: 'app-browser-feature',
  template: `
    <div>
      <p>Window width: {{ windowWidth() }}</p>
      <p>Is touch device: {{ isTouchDevice() }}</p>
    </div>
  `
})
export class BrowserFeatureComponent implements OnInit {
  windowWidth = signal(0);
  isTouchDevice = signal(false);

  constructor(@Inject(PLATFORM_ID) private platformId: object) {}

  ngOnInit(): void {
    if (isPlatformBrowser(this.platformId)) {
      // Safe to access browser APIs
      this.windowWidth.set(window.innerWidth);
      this.isTouchDevice.set('ontouchstart' in window);

      // Set up resize listener
      window.addEventListener('resize', () => {
        this.windowWidth.set(window.innerWidth);
      });
    }
  }
}
```

## Debugging Hydration

### Enable Debug Mode

Enable hydration debugging to identify issues.

```typescript theme={null}
import { bootstrapApplication } from '@angular/platform-browser';
import { 
  provideClientHydration,
  withDebugTracing
} from '@angular/platform-browser';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, {
  providers: [
    provideClientHydration(
      withDebugTracing()
    )
  ]
});
```

This will log hydration information to the console:

```
Angular hydration: Found 42 nodes to hydrate
Angular hydration: Successfully hydrated component AppComponent
Angular hydration: Hydration completed in 125ms
```

### Common Hydration Errors

<Warning>
  **Hydration Mismatch**: Server and client rendered different content.
</Warning>

```typescript theme={null}
// ❌ Causes hydration mismatch
import { Component } from '@angular/core';

@Component({
  selector: 'app-time',
  template: `<p>Current time: {{ currentTime }}</p>`
})
export class TimeComponent {
  // Different value on server vs client!
  currentTime = new Date().toISOString();
}

// ✅ Fixed: Consistent rendering
import { Component, OnInit, signal } from '@angular/core';

@Component({
  selector: 'app-time',
  template: `<p>Current time: {{ currentTime() }}</p>`
})
export class TimeComponent implements OnInit {
  currentTime = signal('Loading...');

  ngOnInit(): void {
    // Update after hydration
    if (typeof window !== 'undefined') {
      setTimeout(() => {
        this.currentTime.set(new Date().toISOString());
      }, 0);
    }
  }
}
```

## Performance Monitoring

Monitor hydration performance in your application.

```typescript theme={null}
import { 
  Component, 
  OnInit, 
  ApplicationRef,
  inject 
} from '@angular/core';

@Component({
  selector: 'app-root',
  template: `<router-outlet></router-outlet>`
})
export class AppComponent implements OnInit {
  private appRef = inject(ApplicationRef);

  ngOnInit(): void {
    // Monitor when app becomes stable (hydration complete)
    this.appRef.isStable.subscribe(stable => {
      if (stable) {
        const hydrationTime = performance.now();
        console.log(`Hydration completed in ${hydrationTime}ms`);
        
        // Report to analytics
        this.reportHydrationMetrics(hydrationTime);
      }
    });
  }

  private reportHydrationMetrics(time: number): void {
    // Send to your analytics service
    if (typeof window !== 'undefined' && 'gtag' in window) {
      (window as any).gtag('event', 'hydration_complete', {
        value: Math.round(time),
        event_category: 'performance'
      });
    }
  }
}
```

## Testing with Hydration

```typescript theme={null}
import { TestBed } from '@angular/core/testing';
import { provideClientHydration } from '@angular/platform-browser';
import { MyComponent } from './my.component';

describe('MyComponent with Hydration', () => {
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [MyComponent],
      providers: [
        provideClientHydration()
      ]
    }).compileComponents();
  });

  it('should hydrate correctly', async () => {
    const fixture = TestBed.createComponent(MyComponent);
    
    // Wait for hydration to complete
    await fixture.whenStable();
    
    const element = fixture.nativeElement;
    expect(element.textContent).toContain('Expected content');
  });
});
```

## Best Practices

<CardGroup cols={2}>
  <Card title="Avoid Direct DOM Access" icon="ban">
    Use Angular's templating and rendering APIs instead of direct DOM manipulation.
  </Card>

  <Card title="Consistent Rendering" icon="equals">
    Ensure server and client render identical content for successful hydration.
  </Card>

  <Card title="Use Platform Checks" icon="shield-check">
    Check platform before accessing browser-only APIs.
  </Card>

  <Card title="Monitor Performance" icon="chart-line">
    Track hydration metrics to identify and fix performance issues.
  </Card>
</CardGroup>

### Hydration Checklist

<Check>Enable `provideClientHydration()` in your application</Check>
<Check>Avoid random values or timestamps in templates</Check>
<Check>Use platform checks for browser APIs</Check>
<Check>Test hydration in development and production modes</Check>
<Check>Monitor hydration performance metrics</Check>
<Check>Handle third-party libraries with `ngSkipHydration`</Check>

## Troubleshooting

### Content Mismatch

If you see hydration mismatch warnings:

1. Check for random values or timestamps
2. Verify async operations complete before rendering
3. Ensure consistent data between server and client
4. Look for browser-only code running during SSR

### Performance Issues

If hydration is slow:

1. Enable incremental hydration for large apps
2. Lazy load non-critical components
3. Optimize server rendering time
4. Reduce bundle size
5. Use event replay for better perceived performance

## Additional Resources

* [Server-Side Rendering](/advanced/ssr)
* [Angular Hydration Guide](https://angular.dev/guide/hydration)
* [Performance Best Practices](https://angular.dev/best-practices/runtime-performance)
