Providers

Google Cloud Storage

Set up Google Cloud Storage for scalable, global file uploads

Using Google Cloud Storage

Set up Google Cloud Storage (GCS) for scalable, global file uploads with Google's infrastructure.

Why Choose Google Cloud Storage?

  • 🌍 Global Infrastructure: Google's worldwide network for fast access
  • 🔗 S3 Compatible: Works with S3-compatible libraries via XML API
  • 💰 Competitive Pricing: Cost-effective with multiple storage classes
  • 🔒 Enterprise Security: Google-grade security and compliance
  • ⚡ High Performance: Optimized for speed and reliability

1. Create a GCS Bucket

Using Google Cloud Console

  1. Go to Google Cloud Console
  2. Select or create a project
  3. Click "Create bucket"
  4. Configure your bucket:
    • Name: Choose a globally unique name (e.g., my-app-uploads-bucket)
    • Location: Choose region closest to your users
    • Storage class: Standard (for frequently accessed files)
    • Access control: Fine-grained (recommended)
  5. Click "Create"

Using gcloud CLI

# Install gcloud CLI (if not already installed)
curl https://sdk.cloud.google.com | bash
exec -l $SHELL
gcloud init

# Create bucket
gsutil mb -p your-project-id -c STANDARD -l us-central1 gs://my-app-uploads-bucket

2. Configure Public Access (Optional)

For Public Files (Images, Documents)

# Make bucket publicly readable
gsutil iam ch allUsers:objectViewer gs://my-app-uploads-bucket

# Or using Console:
# Storage → Bucket → Permissions → Add → "allUsers" → "Storage Object Viewer"

For Private Files

Keep default settings - files will only be accessible via signed URLs.

3. Create Service Account

  1. Go to IAM & Admin
  2. Click "Create Service Account"
  3. Enter details:
    • Name: upload-service
    • Description: "Service account for file uploads"
  4. Click "Create and Continue"
  5. Grant roles:
    • Storage Admin (or Storage Object Admin for bucket-specific access)
  6. Click "Continue""Done"

4. Generate Service Account Key

  1. Click on your service account
  2. Go to "Keys" tab
  3. Click "Add Key""Create new key"
  4. Choose "JSON" format
  5. Download and securely store the JSON file

5. Configure CORS

# Create cors.json file
cat > cors.json << EOF
[
  {
    "origin": ["http://localhost:3000", "https://yourdomain.com"],
    "method": ["GET", "PUT", "POST", "DELETE", "HEAD"],
    "responseHeader": ["Content-Type", "ETag", "Content-Length"],
    "maxAgeSeconds": 3600
  }
]
EOF

# Apply CORS configuration
gsutil cors set cors.json gs://my-app-uploads-bucket

6. Configure Your App

Add to your .env.local:

# Google Cloud Storage Configuration
GOOGLE_APPLICATION_CREDENTIALS=./path/to/service-account-key.json
GCS_PROJECT_ID=your-project-id
GCS_BUCKET_NAME=my-app-uploads-bucket

# Optional: Custom domain for public files
GCS_PUBLIC_URL=https://storage.googleapis.com/my-app-uploads-bucket
# Or with custom domain: GCS_PUBLIC_URL=https://uploads.yourdomain.com

7. Update Your Upload Configuration

// lib/upload.ts
import { createUploadConfig } from "pushduck/server";

export const { s3,  } = createUploadConfig()
  .provider("gcs",{
    projectId: process.env.GCS_PROJECT_ID!,
    keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS!,
    bucket: process.env.GCS_BUCKET_NAME!,
    // Optional: Custom public URL
    publicUrl: process.env.GCS_PUBLIC_URL,
  })
  .defaults({
    maxFileSize: "100MB", // GCS supports large files
    acl: "publicRead", // For public access
  })
  .build();

8. Test Your Setup

npx @pushduck/cli@latest test --provider gcs

This will verify your GCS connection and upload a test file.

✅ You're Ready!

Your Google Cloud Storage is configured! Benefits:

  • Global performance via Google's network
  • Automatic scaling to handle any load
  • Enterprise-grade security and compliance
  • Multiple storage classes for cost optimization

🌐 Advanced Features

Multi-Regional Storage

// Configure multi-regional bucket for global performance
export const { s3,  } = createUploadConfig()
  .provider("gcs",{
    // ... basic config
    bucket: process.env.GCS_BUCKET_NAME!,
    // Multi-regional configuration
    location: "US", // or "EU", "ASIA"
    storageClass: "MULTI_REGIONAL",
  })
  .build();

Storage Classes

Optimize costs with different storage classes:

// Configure lifecycle policies for cost optimization
.hooks({
  onUploadComplete: async ({ file, key, metadata }) => {
    // Move old files to cheaper storage classes
    if (metadata.category === 'archive') {
      await moveToStorageClass(key, 'COLDLINE');
    } else if (metadata.category === 'backup') {
      await moveToStorageClass(key, 'ARCHIVE');
    }
  }
})

CDN Integration

// Use Cloud CDN for faster global delivery
export const { s3,  } = createUploadConfig()
  .provider("gcs",{
    // ... config
    // Configure CDN endpoint
    cdnUrl: "https://your-cdn-domain.com",
    // Cache control headers
    defaultCacheControl: "public, max-age=31536000",
  })
  .build();

🔒 Security Best Practices

Bucket-Level IAM

# Create custom role with minimal permissions
gcloud iam roles create upload_service_role \
  --project=your-project-id \
  --title="Upload Service Role" \
  --permissions="storage.objects.create,storage.objects.get"

# Bind role to service account
gcloud projects add-iam-policy-binding your-project-id \
  --member="serviceAccount:upload-service@your-project-id.iam.gserviceaccount.com" \
  --role="projects/your-project-id/roles/upload_service_role"

Object-Level Security

// Implement user-based access control
.middleware(async ({ req, file }) => {
  const user = await authenticate(req);

  // Generate user-specific path
  const userPath = `users/${user.id}/${file.name}`;

  return {
    userId: user.id,
    keyPrefix: `users/${user.id}/`,
    metadata: {
      uploadedBy: user.id,
      uploadedAt: new Date().toISOString(),
    }
  };
})

Signed URLs for Private Access

// Generate time-limited access URLs
.hooks({
  onUploadComplete: async ({ file, key }) => {
    if (file.private) {
      // Generate signed URL valid for 1 hour
      const signedUrl = await generateSignedUrl(key, {
        action: 'read',
        expires: Date.now() + 60 * 60 * 1000, // 1 hour
      });

      return { ...file, url: signedUrl };
    }
    return file;
  }
})

💰 Cost Optimization

Storage Class Strategy

Use CaseStorage ClassCostAccess Pattern
Active filesStandardHigherFrequent access
BackupsNearlineMediumMonthly access
ArchivesColdlineLowerQuarterly access
Long-termArchiveLowestYearly access

Lifecycle Management

// Automatic lifecycle transitions
const lifecyclePolicy = {
  rule: [
    {
      action: { type: "SetStorageClass", storageClass: "NEARLINE" },
      condition: { age: 30 }, // Move to Nearline after 30 days
    },
    {
      action: { type: "SetStorageClass", storageClass: "COLDLINE" },
      condition: { age: 90 }, // Move to Coldline after 90 days
    },
    {
      action: { type: "Delete" },
      condition: { age: 365 }, // Delete after 1 year
    },
  ],
};

📊 Monitoring & Analytics

Cloud Monitoring Integration

// Track upload metrics
.hooks({
  onUploadStart: async ({ file }) => {
    await cloudMonitoring.createTimeSeries({
      name: 'custom.googleapis.com/upload/started',
      value: 1,
      labels: {
        file_type: file.type,
        file_size_mb: Math.round(file.size / 1024 / 1024),
      }
    });
  },
  onUploadComplete: async ({ file, metadata }) => {
    await cloudMonitoring.createTimeSeries({
      name: 'custom.googleapis.com/upload/completed',
      value: metadata.uploadDuration,
      labels: {
        success: 'true',
        provider: 'gcs',
      }
    });
  }
})

Usage Analytics

// Track storage usage and costs
const getStorageMetrics = async () => {
  const bucket = storage.bucket(process.env.GCS_BUCKET_NAME!);
  const [metadata] = await bucket.getMetadata();

  return {
    totalSize: metadata.storageClass?.totalBytes,
    objectCount: metadata.storageClass?.objectCount,
    storageClass: metadata.storageClass?.name,
    location: metadata.location,
  };
};

🌐 Custom Domain Setup

1. Verify Domain Ownership

# Add verification record to DNS
# TXT record: google-site-verification=your-verification-code

# Verify domain
gcloud domains verify yourdomain.com

2. Configure CNAME

# Add CNAME record to DNS
# uploads.yourdomain.com -> c.storage.googleapis.com

3. Update Configuration

// Use custom domain for file URLs
export const { s3,  } = createUploadConfig()
  .provider("gcs",{
    // ... config
    customDomain: "https://uploads.yourdomain.com",
  })
  .build();

🆘 Common Issues

Authentication errors? → Check service account key path and permissions
CORS errors? → Verify CORS configuration and allowed origins
Access denied? → Check IAM roles and bucket permissions
Slow uploads? → Choose region closer to your users
Quota exceeded? → Check project quotas and billing account

🚀 Performance Tips

  1. Choose the right region - closest to your users
  2. Use multi-regional for global applications
  3. Enable CDN for frequently accessed files
  4. Optimize image sizes before upload
  5. Use parallel uploads for multiple files
  6. Implement proper caching headers

Next: Upload Your First Image or check out our Examples