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

# Deployment and CI/CD

> Best practices for deploying frontend applications and implementing continuous integration and delivery pipelines

## Introduction to Frontend Deployment and CI/CD

Deploying frontend applications and implementing effective CI/CD (Continuous Integration/Continuous Delivery) pipelines are crucial aspects of modern frontend development. This guide covers best practices for deploying frontend applications to various environments and setting up automated workflows to ensure reliable, consistent deployments.

<CardGroup cols={2}>
  <Card title="Deployment Strategies" icon="rocket">
    Learn about different deployment approaches for frontend applications.
  </Card>

  {' '}

  <Card title="CI/CD Pipelines" icon="conveyor-belt">
    Implement automated workflows for testing, building, and deploying your
    applications.
  </Card>

  {' '}

  <Card title="Environment Management" icon="sitemap">
    Manage different environments (development, staging, production) effectively.
  </Card>

  <Card title="Performance Monitoring" icon="chart-line">
    Monitor your deployed applications for performance and errors.
  </Card>
</CardGroup>

## Frontend Deployment Fundamentals

### Understanding the Frontend Deployment Process

Deploying a frontend application typically involves these steps:

1. **Building the application**: Compiling, bundling, and optimizing the code for production
2. **Asset optimization**: Minifying code, optimizing images, and generating asset manifests
3. **Uploading to hosting**: Transferring the built files to a hosting provider
4. **Configuring the environment**: Setting up environment variables, CDN, and caching
5. **Validating the deployment**: Testing the deployed application

### Static vs. Server-Rendered Deployments

#### Static Site Deployment

Static sites consist of HTML, CSS, JavaScript, and other assets that don't require server-side rendering at request time.

**Advantages:**

* Simpler deployment process
* Can be served from CDNs for better performance
* Lower hosting costs
* Better security due to reduced attack surface

**Common hosting options:**

* Netlify
* Vercel
* GitHub Pages
* AWS S3 + CloudFront
* Firebase Hosting
* Cloudflare Pages

#### Server-Rendered Deployment

Server-rendered applications generate HTML on the server for each request.

**Advantages:**

* Better SEO potential
* Faster initial page load
* Works better for dynamic content

**Common hosting options:**

* Vercel
* Netlify
* Heroku
* AWS Elastic Beanstalk
* Google App Engine
* DigitalOcean App Platform

### Deployment Strategies

#### Basic Deployment

The simplest deployment strategy involves building your application and uploading it to a hosting provider.

```bash theme={null}
# Build the application
npm run build

# Deploy to hosting provider
npx netlify deploy --prod
```

#### Blue-Green Deployment

Blue-green deployment involves maintaining two identical production environments (blue and green). At any time, only one environment is live and serving production traffic.

1. Deploy new version to the inactive environment (e.g., green)
2. Test the new deployment
3. Switch traffic from active (blue) to inactive (green)
4. The previously active environment (blue) becomes inactive

**Benefits:**

* Zero downtime deployments
* Easy rollback by switching back to the previous environment
* Reduced risk as the new version is fully tested before receiving traffic

#### Canary Deployment

Canary deployment involves gradually routing a small percentage of traffic to the new version.

1. Deploy the new version alongside the current version
2. Route a small percentage (e.g., 5%) of traffic to the new version
3. Monitor for errors and performance issues
4. Gradually increase traffic to the new version
5. Once confident, route 100% of traffic to the new version

**Benefits:**

* Reduced risk by limiting exposure to the new version
* Ability to test with real users and traffic
* Early detection of issues that might not appear in testing environments

#### Feature Flags

Feature flags allow you to toggle features on or off without deploying new code.

```javascript theme={null}
// Example of a feature flag in code
if (featureFlags.isEnabled('new-ui')) {
  // Show new UI
  renderNewUI();
} else {
  // Show old UI
  renderOldUI();
}
```

**Benefits:**

* Decouple deployment from feature release
* Test features with specific user segments
* Quick rollback by disabling problematic features
* A/B testing capabilities

## Hosting Providers and Deployment Platforms

### Static Site Hosting

#### Netlify

Netlify is a popular platform for deploying static sites and serverless functions.

**Setup:**

1. Create a `netlify.toml` configuration file:

```toml theme={null}
[build]
  command = "npm run build"
  publish = "dist"

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200
```

2. Deploy using the Netlify CLI:

```bash theme={null}
npx netlify deploy --prod
```

**Key features:**

* Continuous deployment from Git
* Branch deploys and deploy previews
* Serverless functions
* Form handling
* Split testing

#### Vercel

Vercel is a cloud platform for static sites and serverless functions, optimized for frontend frameworks.

**Setup:**

1. Create a `vercel.json` configuration file:

```json theme={null}
{
  "version": 2,
  "builds": [
    {
      "src": "package.json",
      "use": "@vercel/static-build",
      "config": { "distDir": "dist" }
    }
  ],
  "routes": [
    { "handle": "filesystem" },
    { "src": "/.*", "dest": "/index.html" }
  ]
}
```

2. Deploy using the Vercel CLI:

```bash theme={null}
vercel --prod
```

**Key features:**

* Optimized for Next.js, but supports many frameworks
* Preview deployments for every Git branch
* Serverless functions
* Edge network for global distribution
* Built-in analytics

#### AWS S3 + CloudFront

AWS S3 combined with CloudFront provides a scalable, cost-effective solution for hosting static sites.

**Setup:**

1. Create an S3 bucket and configure it for static website hosting
2. Set up CloudFront distribution pointing to the S3 bucket
3. Deploy using the AWS CLI:

```bash theme={null}
# Build the application
npm run build

# Sync files to S3
aws s3 sync dist/ s3://your-bucket-name/ --delete

# Invalidate CloudFront cache
aws cloudfront create-invalidation --distribution-id YOUR_DISTRIBUTION_ID --paths "/*"
```

**Key features:**

* Highly scalable and reliable
* Low cost for high traffic sites
* Global content delivery via CloudFront
* Fine-grained access control

### Server-Rendered Hosting

#### Heroku

Heroku is a platform as a service (PaaS) that enables developers to build, run, and operate applications entirely in the cloud.

**Setup:**

1. Create a `Procfile` in your project root:

```
web: npm start
```

2. Deploy using the Heroku CLI:

```bash theme={null}
git push heroku main
```

**Key features:**

* Simple deployment workflow
* Automatic scaling
* Add-ons for databases and other services
* Built-in logging and monitoring

#### DigitalOcean App Platform

DigitalOcean App Platform is a PaaS solution that simplifies deploying and scaling applications.

**Setup:**

Create a `app.yaml` configuration file:

```yaml theme={null}
name: my-frontend-app
services:
  - name: web
    github:
      repo: username/repo-name
      branch: main
    build_command: npm run build
    run_command: npm start
    http_port: 8080
    instance_count: 1
    instance_size_slug: basic-xs
    routes:
      - path: /
```

**Key features:**

* Simple pricing model
* Global CDN
* Managed databases
* Automatic HTTPS

## Continuous Integration and Continuous Delivery (CI/CD)

### CI/CD Fundamentals

CI/CD is a method to frequently deliver apps to customers by introducing automation into the development stages.

* **Continuous Integration (CI)**: Automatically building and testing code changes
* **Continuous Delivery (CD)**: Automatically deploying code changes to staging or production environments

### Setting Up CI/CD Pipelines

#### GitHub Actions

GitHub Actions allows you to automate your workflow directly from your GitHub repository.

**Example workflow for a React application:**

```yaml theme={null}
# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '16'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

      - name: Build
        run: npm run build
        env:
          REACT_APP_API_URL: ${{ secrets.API_URL }}

      - name: Deploy to Netlify
        uses: netlify/actions/cli@master
        with:
          args: deploy --dir=build --prod
        env:
          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
```

#### GitLab CI/CD

GitLab CI/CD is a tool built into GitLab for software development through continuous integration and delivery.

**Example `.gitlab-ci.yml` for a Vue.js application:**

```yaml theme={null}
stages:
  - test
  - build
  - deploy

cache:
  paths:
    - node_modules/

test:
  stage: test
  image: node:16
  script:
    - npm ci
    - npm run lint
    - npm run test:unit

build:
  stage: build
  image: node:16
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - dist/

deploy_staging:
  stage: deploy
  image: alpine:latest
  script:
    - apk add --no-cache curl
    - curl -X POST -d '{"deploy_to":"staging"}' -H "Authorization: Bearer $DEPLOY_TOKEN" $DEPLOY_HOOK_URL
  environment:
    name: staging
    url: https://staging.example.com
  only:
    - develop

deploy_production:
  stage: deploy
  image: alpine:latest
  script:
    - apk add --no-cache curl
    - curl -X POST -d '{"deploy_to":"production"}' -H "Authorization: Bearer $DEPLOY_TOKEN" $DEPLOY_HOOK_URL
  environment:
    name: production
    url: https://example.com
  only:
    - main
  when: manual
```

#### CircleCI

CircleCI is a cloud-based CI/CD service that automates the build, test, and deployment process.

**Example `.circleci/config.yml` for an Angular application:**

```yaml theme={null}
version: 2.1

jobs:
  build-and-test:
    docker:
      - image: cimg/node:16.13
    steps:
      - checkout
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "package-lock.json" }}
            - v1-dependencies-
      - run: npm ci
      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "package-lock.json" }}
      - run: npm run lint
      - run: npm run test -- --no-watch --no-progress --browsers=ChromeHeadlessCI
      - run: npm run build -- --configuration production
      - persist_to_workspace:
          root: .
          paths:
            - dist

  deploy:
    docker:
      - image: cimg/node:16.13
    steps:
      - checkout
      - attach_workspace:
          at: .
      - run:
          name: Install Firebase Tools
          command: npm install -g firebase-tools
      - run:
          name: Deploy to Firebase
          command: firebase deploy --token "$FIREBASE_TOKEN" --only hosting

workflows:
  version: 2
  build-test-deploy:
    jobs:
      - build-and-test
      - deploy:
          requires:
            - build-and-test
          filters:
            branches:
              only: main
```

### Environment-Specific Configurations

Managing different configurations for development, staging, and production environments is crucial for a robust deployment pipeline.

#### Environment Variables

Environment variables are a common way to manage environment-specific configurations.

**React with Create React App:**

Create environment-specific files:

* `.env.development`
* `.env.test`
* `.env.production`

```
# .env.production
REACT_APP_API_URL=https://api.example.com
REACT_APP_FEATURE_FLAG_NEW_UI=true
```

**Vue.js:**

Create environment-specific files:

* `.env.development`
* `.env.test`
* `.env.production`

```
# .env.production
VUE_APP_API_URL=https://api.example.com
VUE_APP_FEATURE_FLAG_NEW_UI=true
```

**Angular:**

Create environment-specific files in the `src/environments` directory:

* `environment.ts`
* `environment.prod.ts`

```typescript theme={null}
// environment.prod.ts
export const environment = {
  production: true,
  apiUrl: 'https://api.example.com',
  featureFlags: {
    newUi: true,
  },
};
```

#### Runtime Configuration

Sometimes you need to load configuration at runtime rather than build time.

**Example using a config.json file:**

```javascript theme={null}
// Load configuration at runtime
async function loadConfig() {
  try {
    const response = await fetch('/config.json');
    return await response.json();
  } catch (error) {
    console.error('Failed to load configuration:', error);
    return {};
  }
}

// Usage
loadConfig().then((config) => {
  console.log('API URL:', config.apiUrl);
  initializeApp(config);
});
```

## Optimizing the Deployment Process

### Build Optimization

#### Reducing Bundle Size

```javascript theme={null}
// webpack.config.js for a React application
const TerserPlugin = require('terser-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');

module.exports = {
  // ...
  optimization: {
    minimizer: [new TerserPlugin()],
    splitChunks: {
      chunks: 'all',
      maxInitialRequests: Infinity,
      minSize: 0,
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name(module) {
            // Get the name of the npm package
            const packageName = module.context.match(
              /[\\/]node_modules[\\/](.+?)(?:[\\/]|$)/
            )[1];
            return `npm.${packageName.replace('@', '')}`;
          },
        },
      },
    },
  },
  plugins: [
    // ...
    new CompressionPlugin({
      algorithm: 'gzip',
      test: /\.(js|css|html|svg)$/,
      threshold: 10240,
      minRatio: 0.8,
    }),
  ],
};
```

#### Tree Shaking

Tree shaking is a term commonly used in the JavaScript context for dead-code elimination.

```javascript theme={null}
// Import only what you need
// Good - only imports Button
import { Button } from 'ui-library';

// Bad - imports the entire library
import UILibrary from 'ui-library';
const { Button } = UILibrary;
```

#### Code Splitting

Code splitting is a technique to split your code into various bundles which can then be loaded on demand.

**React with React.lazy and Suspense:**

```jsx theme={null}
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));
const Contact = lazy(() => import('./routes/Contact'));

function App() {
  return (
    <Router>
      <Suspense fallback={<div>Loading...</div>}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/contact" element={<Contact />} />
        </Routes>
      </Suspense>
    </Router>
  );
}
```

**Vue.js with dynamic imports:**

```javascript theme={null}
// router.js
const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import('./views/Home.vue'),
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('./views/About.vue'),
  },
  {
    path: '/contact',
    name: 'Contact',
    component: () => import('./views/Contact.vue'),
  },
];
```

### Caching Strategies

#### Cache Headers

Proper cache headers ensure that browsers cache assets appropriately.

**Example Netlify `_headers` file:**

```
# _headers
/assets/*
  Cache-Control: public, max-age=31536000, immutable

/*.html
  Cache-Control: public, max-age=0, must-revalidate

/*.js
  Cache-Control: public, max-age=31536000, immutable

/*.css
  Cache-Control: public, max-age=31536000, immutable
```

#### Cache Busting

Cache busting is a technique that prevents browsers from using cached versions of assets when they've been updated.

**Webpack content hash:**

```javascript theme={null}
// webpack.config.js
module.exports = {
  // ...
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
  },
};
```

### Automated Testing in CI/CD

#### Unit Tests

```yaml theme={null}
# GitHub Actions workflow with Jest
name: Test

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '16'
          cache: 'npm'
      - run: npm ci
      - run: npm test
```

#### End-to-End Tests

```yaml theme={null}
# GitHub Actions workflow with Cypress
name: E2E Tests

on: [push, pull_request]

jobs:
  cypress-run:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Cypress run
        uses: cypress-io/github-action@v5
        with:
          build: npm run build
          start: npm start
          wait-on: 'http://localhost:3000'
```

## Monitoring and Observability

### Error Tracking

#### Sentry Integration

```javascript theme={null}
// index.js for a React application
import React from 'react';
import ReactDOM from 'react-dom';
import * as Sentry from '@sentry/react';
import { BrowserTracing } from '@sentry/tracing';
import App from './App';

Sentry.init({
  dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0',
  integrations: [new BrowserTracing()],
  tracesSampleRate: 1.0,
});

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);
```

### Performance Monitoring

#### Web Vitals

```javascript theme={null}
// reportWebVitals.js
import { getCLS, getFID, getLCP, getFCP, getTTFB } from 'web-vitals';

const reportWebVitals = (onPerfEntry) => {
  if (onPerfEntry && onPerfEntry instanceof Function) {
    getCLS(onPerfEntry);
    getFID(onPerfEntry);
    getLCP(onPerfEntry);
    getFCP(onPerfEntry);
    getTTFB(onPerfEntry);
  }
};

export default reportWebVitals;
```

```javascript theme={null}
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

// Send web vitals to analytics
reportWebVitals(({ name, delta, id }) => {
  // Send to Google Analytics
  gtag('event', name, {
    event_category: 'Web Vitals',
    event_label: id,
    value: Math.round(name === 'CLS' ? delta * 1000 : delta),
    non_interaction: true,
  });
});
```

### Logging

#### Centralized Logging

```javascript theme={null}
// logger.js
class Logger {
  constructor() {
    this.logs = [];
    this.maxLogs = 100;
  }

  log(level, message, data = {}) {
    const logEntry = {
      timestamp: new Date().toISOString(),
      level,
      message,
      data,
    };

    this.logs.push(logEntry);

    // Keep logs under the maximum size
    if (this.logs.length > this.maxLogs) {
      this.logs.shift();
    }

    // Log to console in development
    if (process.env.NODE_ENV === 'development') {
      console[level](message, data);
    }

    // Send to centralized logging service in production
    if (process.env.NODE_ENV === 'production') {
      this.sendToLoggingService(logEntry);
    }
  }

  async sendToLoggingService(logEntry) {
    try {
      await fetch('https://logging.example.com/api/logs', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(logEntry),
      });
    } catch (error) {
      // Fallback to console in case of failure
      console.error('Failed to send log to logging service:', error);
    }
  }

  info(message, data) {
    this.log('info', message, data);
  }

  warn(message, data) {
    this.log('warn', message, data);
  }

  error(message, data) {
    this.log('error', message, data);
  }

  debug(message, data) {
    this.log('debug', message, data);
  }
}

export const logger = new Logger();
```

## Rollback Strategies

### Manual Rollback

```bash theme={null}
# Example rollback command for Netlify
npx netlify deploy --prod --dir=build --site-id=$SITE_ID --auth=$AUTH_TOKEN --message="Rolling back to previous version"

# Example rollback command for Vercel
vercel rollback --prod
```

### Automated Rollback

```yaml theme={null}
# GitHub Actions workflow with automated rollback
name: Deploy with Rollback

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '16'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Deploy
        id: deploy
        run: |
          DEPLOY_OUTPUT=$(npx netlify deploy --prod --json)
          DEPLOY_ID=$(echo $DEPLOY_OUTPUT | jq -r '.deployId')
          echo "::set-output name=deploy_id::$DEPLOY_ID"
        env:
          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}

      - name: Test deployment
        id: test_deployment
        run: |
          # Run tests against the deployed site
          RESPONSE_CODE=$(curl -s -o /dev/null -w "%{http_code}" https://example.com)
          if [[ "$RESPONSE_CODE" -ne 200 ]]; then
            echo "Deployment failed with response code $RESPONSE_CODE"
            exit 1
          fi

      - name: Rollback on failure
        if: failure() && steps.deploy.outputs.deploy_id != ''
        run: |
          npx netlify deploy --prod-id=${{ steps.deploy.outputs.deploy_id }} --restore
        env:
          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
```

## Conclusion

Implementing effective deployment and CI/CD practices is essential for modern frontend development. By following the best practices outlined in this guide, you can create reliable, automated workflows that ensure your applications are deployed consistently and with minimal risk.

Remember these key takeaways:

1. **Choose the right deployment strategy** for your application's needs, whether it's static hosting, server-rendered, or a hybrid approach.

2. **Automate your workflow** with CI/CD pipelines to ensure consistent testing, building, and deployment.

3. **Implement proper environment management** to handle different configurations for development, staging, and production.

4. **Optimize your build process** to reduce bundle sizes, implement code splitting, and ensure efficient caching.

5. **Monitor your deployed applications** for errors, performance issues, and user experience metrics.

6. **Have a rollback strategy** in place to quickly recover from problematic deployments.

By implementing these practices, you'll create a robust deployment process that supports your team's ability to deliver high-quality frontend applications efficiently and reliably.
