> ## Documentation Index
> Fetch the complete documentation index at: https://www.commercengine.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Node JS

> Complete guide to using the SDK in Node.js backend applications

The SDK works excellently in Node.js applications for backend services, APIs, and server-side e-commerce operations.

### NPM Package

<Card title="@commercengine/storefront" icon="npm" href="https://www.npmjs.com/package/@commercengine/storefront">
  Node.js integration for Commerce Engine Storefront SDK.
</Card>

## Installation

Install the SDK in your Node.js project:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @commercengine/storefront
# or
pnpm install @commercengine/storefront
```

## Basic Setup

Configure the SDK for server-side usage:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// src/lib/storefront.ts
import { StorefrontSDK, Environment, MemoryTokenStorage } from '@commercengine/storefront';

const storefront = createStorefront({
  storeId: process.env.STORE_ID!,
  environment: process.env.NODE_ENV === 'production' ? Environment.Production : Environment.Staging,
  apiKey: process.env.CE_API_KEY!,
  tokenStorage: new MemoryTokenStorage(), // For server-side token management
  timeout: 30000 // 30 second timeout
});

export default storefront;
```

## Environment Variables

Set up your environment configuration:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
# .env
STORE_ID=your_store_id
CE_API_KEY=your_api_key
NODE_ENV=development
```

## Token Management Strategies

### Memory Storage (Default)

For simple server applications or stateless operations:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { MemoryTokenStorage } from '@commercengine/storefront';

const client = createStorefront({
  storeId: process.env.STORE_ID!,
  apiKey: process.env.CE_API_KEY!,
  tokenStorage: new MemoryTokenStorage()
});
```

### Database Integration

For persistent token storage across server restarts:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { TokenStorage } from '@commercengine/storefront';

class DatabaseTokenStorage implements TokenStorage {
  private userId: string;

  constructor(userId: string) {
    this.userId = userId;
  }

  async getAccessToken(): Promise<string | null> {
    const user = await User.findById(this.userId);
    return user?.accessToken || null;
  }

  async setAccessToken(token: string): Promise<void> {
    await User.findByIdAndUpdate(this.userId, { accessToken: token });
  }

  async getRefreshToken(): Promise<string | null> {
    const user = await User.findById(this.userId);
    return user?.refreshToken || null;
  }

  async setRefreshToken(token: string): Promise<void> {
    await User.findByIdAndUpdate(this.userId, { refreshToken: token });
  }

  async clearTokens(): Promise<void> {
    await User.findByIdAndUpdate(this.userId, { 
      accessToken: null, 
      refreshToken: null 
    });
  }
}

// Usage with user-specific tokens
const userClient = createStorefront({
  storeId: process.env.STORE_ID!,
  apiKey: process.env.CE_API_KEY!,
  tokenStorage: new DatabaseTokenStorage('user-123')
});
```

### Redis Integration

For distributed systems with shared token storage:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
import Redis from 'ioredis';
import { TokenStorage } from '@commercengine/storefront';

class RedisTokenStorage implements TokenStorage {
  private redis: Redis;
  private keyPrefix: string;

  constructor(redis: Redis, userId: string) {
    this.redis = redis;
    this.keyPrefix = `storefront:${userId}`;
  }

  async getAccessToken(): Promise<string | null> {
    return await this.redis.get(`${this.keyPrefix}:access_token`);
  }

  async setAccessToken(token: string): Promise<void> {
    await this.redis.setex(`${this.keyPrefix}:access_token`, 3600, token); // 1 hour expiry
  }

  async getRefreshToken(): Promise<string | null> {
    return await this.redis.get(`${this.keyPrefix}:refresh_token`);
  }

  async setRefreshToken(token: string): Promise<void> {
    await this.redis.setex(`${this.keyPrefix}:refresh_token`, 86400, token); // 24 hour expiry
  }

  async clearTokens(): Promise<void> {
    await this.redis.del(
      `${this.keyPrefix}:access_token`,
      `${this.keyPrefix}:refresh_token`
    );
  }
}
```

## Express.js Integration

### Basic Express Setup

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
import express from 'express';
import storefront from './lib/storefront';

const app = express();
app.use(express.json());

app.get('/api/products', async (req, res) => {
  try {
    const { data, error } = await storefront.catalog.listProducts({
      limit: parseInt(req.query.limit as string) || 20
    });

    if (error) {
      return res.status(400).json({ error: error.message });
    }
    res.json(data);
  } catch (error) {
    res.status(500).json({ error: 'Internal server error' });
  }
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});
```

### Middleware for User Context

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { Request, Response, NextFunction } from 'express';

interface AuthenticatedRequest extends Request {
  userClient?: StorefrontSDK;
  userId?: string;
}

const authenticateUser = async (req: AuthenticatedRequest, res: Response, next: NextFunction) => {
  const authHeader = req.headers.authorization;
  if (!authHeader) {
    return res.status(401).json({ error: 'Authorization header required' });
  }

  const token = authHeader.replace('Bearer ', '');
  
  // Create user-specific SDK instance
  req.userClient = createStorefront({
    storeId: process.env.STORE_ID!,
    apiKey: process.env.CE_API_KEY!,
    accessToken: token // Manual token management
  });

  // Verify token by getting user info
  const { data: userData, error } = await req.userClient.auth.retrieveUser();
  if (error) {
    return res.status(401).json({ error: 'Invalid token' });
  }

  req.userId = userData?.user.id;
  next();
};

// Protected routes
app.get('/api/cart', authenticateUser, async (req: AuthenticatedRequest, res) => {
  const { data, error } = await req.userClient!.cart.getUserCart({ user_id: req.userId! });

  if (error) {
    return res.status(400).json({ error: error.message });
  }
  res.json(data?.cart);
});
```

## Background Jobs

### Order Processing

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { Queue, Worker } from 'bullmq';
import storefront from './lib/storefront';

interface OrderProcessingJob {
  orderId: string;
  userId: string;
}

const orderQueue = new Queue<OrderProcessingJob>('order-processing');

const orderWorker = new Worker<OrderProcessingJob>('order-processing', async (job) => {
  const { orderId, userId } = job.data;
  
  try {
    // Get order details
    const orderResult = await storefront.order.retrieveOrderDetail(orderId);
    if (!orderResult.success) {
      throw new Error(`Failed to retrieve order: ${orderResult.error.message}`);
    }

    // Process order (send emails, update inventory, etc.)
    await processOrderFulfillment(orderResult.data);
    
    console.log(`Order ${orderId} processed successfully`);
  } catch (error) {
    console.error(`Failed to process order ${orderId}:`, error);
    throw error; // Re-throw to mark job as failed
  }
});

// Add job to queue
export async function queueOrderProcessing(orderId: string, userId: string) {
  await orderQueue.add('process-order', { orderId, userId });
}
```

### Webhook Handlers

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
app.post('/webhooks/order-created', async (req, res) => {
  const { order_id, user_id } = req.body;
  
  try {
    // Verify webhook signature here
    
    // Queue background processing
    await queueOrderProcessing(order_id, user_id);
    
    res.status(200).json({ message: 'Webhook processed' });
  } catch (error) {
    console.error('Webhook processing failed:', error);
    res.status(500).json({ error: 'Webhook processing failed' });
  }
});
```

## Microservices Architecture

### Service-to-Service Communication

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// order-service.ts
export class OrderService {
  private storefront: StorefrontSDK;

  constructor() {
    this.storefront = createStorefront({
      storeId: process.env.STORE_ID!,
      apiKey: process.env.CE_API_KEY!,
      tokenStorage: new MemoryTokenStorage()
    });
  }

  async createOrder(userId: string, cartData: any) {
    const result = await this.storefront.order.createOrder({
      user_id: userId,
      ...cartData
    });

    if (result.success) {
      // Emit event for other services
      await this.eventBus.emit('order.created', {
        orderId: result.data.id,
        userId,
        amount: result.data.grand_total
      });
    }

    return result;
  }
}
```

### Health Checks

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
app.get('/health', async (req, res) => {
  try {
    // Test SDK connectivity
    const result = await storefront.helpers.retrieveAllCountries();
    
    if (result.success) {
      res.status(200).json({ 
        status: 'healthy',
        timestamp: new Date().toISOString(),
        sdk: 'connected'
      });
    } else {
      res.status(503).json({ 
        status: 'unhealthy',
        error: 'SDK connection failed'
      });
    }
  } catch (error) {
    res.status(503).json({ 
      status: 'unhealthy',
      error: error.message
    });
  }
});
```

## Error Handling

### Global Error Handler

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { ResponseUtils } from '@commercengine/storefront';

app.use((error: any, req: Request, res: Response, next: NextFunction) => {
  console.error('Unhandled error:', error);

  // Handle SDK-specific errors
  if (error.response && ResponseUtils.isSuccess) {
    const metadata = ResponseUtils.getMetadata(error.response);
    return res.status(metadata.status).json({
      error: 'API request failed',
      details: metadata
    });
  }

  // Generic error response
  res.status(500).json({
    error: 'Internal server error',
    requestId: req.headers['x-request-id']
  });
});
```

### Graceful Shutdown

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
process.on('SIGTERM', async () => {
  console.log('SIGTERM received, shutting down gracefully');
  
  // Close database connections, stop workers, etc.
  await orderWorker.close();
  await redis.disconnect();
  
  process.exit(0);
});
```

## Performance Considerations

### Request Timeouts

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
const client = createStorefront({
  storeId: process.env.STORE_ID!,
  apiKey: process.env.CE_API_KEY!,
  timeout: 10000, // 10 second timeout for backend operations
  debug: process.env.NODE_ENV === 'development'
});
```

### Connection Monitoring

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Monitor SDK performance
const trackAPIPerformance = async (operation: string, fn: () => Promise<any>) => {
  const start = process.hrtime.bigint();
  
  try {
    const result = await fn();
    const duration = Number(process.hrtime.bigint() - start) / 1000000; // Convert to ms
    
    console.log(`SDK operation ${operation} completed in ${duration.toFixed(2)}ms`);
    return result;
  } catch (error) {
    const duration = Number(process.hrtime.bigint() - start) / 1000000;
    console.error(`SDK operation ${operation} failed after ${duration.toFixed(2)}ms:`, error);
    throw error;
  }
};

// Usage
const products = await trackAPIPerformance('listProducts', () =>
  storefront.catalog.listProducts({ limit: 20 })
);
```

## Best Practices

<CardGroup cols={2}>
  <Card title="Environment Configuration" icon="gear">
    Use environment variables for all configuration and never hardcode sensitive values
  </Card>

  <Card title="Error Handling" icon="circle-exclamation">
    Implement comprehensive error handling for all SDK operations with appropriate logging
  </Card>

  <Card title="Token Storage" icon="database">
    Choose appropriate token storage based on your architecture (memory, database, Redis)
  </Card>

  <Card title="Health Monitoring" icon="heart">
    Implement health checks and monitoring to ensure SDK connectivity and performance
  </Card>
</CardGroup>

## Cross-References

* **Token Management**: [Token Management Guide](/docs/sdk/token-management) for authentication patterns
* **Error Handling**: [Error Handling Guide](/docs/sdk/error-handling) for comprehensive error management
* **API Reference**: [API Reference](/docs/api-reference) for endpoint documentation

<Note>
  The SDK is optimized for server-side usage with proper timeout handling and token management. Choose your token storage strategy based on your application architecture and scaling requirements.
</Note>
