Skip to content

Conversation

vedantterse
Copy link

@vedantterse vedantterse commented Oct 20, 2025

User description

Fixes #57

Replaced hardcoded Cloudflare R2 public URL with an environment variable to allow custom bucket configurations.

Changes made:

  • Added R2_PUBLIC_URL to .env.example
  • Updated lib/upload-image.ts to use process.env.R2_PUBLIC_URL instead of the hardcoded URL
  • Updated next.config.ts to read the hostname dynamically from R2_PUBLIC_URL

This makes the setup compatible with any Cloudflare R2 bucket and avoids upload errors for users using their own configuration.


PR Type

Bug fix, Enhancement


Description

  • Replaced hardcoded Cloudflare R2 public URL with environment variable

  • Updated image upload logic to use dynamic R2_PUBLIC_URL configuration

  • Modified Next.js config to extract hostname from environment variable

  • Added R2_PUBLIC_URL to .env.example for user configuration


Diagram Walkthrough

flowchart LR
  A["Hardcoded R2 URL"] -->|"Remove"| B["Environment Variable"]
  B -->|"Configure"| C["lib/upload-image.ts"]
  B -->|"Configure"| D["next.config.ts"]
  B -->|"Document"| E[".env.example"]
Loading

File Walkthrough

Relevant files
Bug fix
upload-image.ts
Use environment variable for R2 public URL                             

lib/upload-image.ts

  • Replaced hardcoded R2 public URL with process.env.R2_PUBLIC_URL
    environment variable
  • Constructs public URL dynamically from environment configuration
+1/-1     
Enhancement
next.config.ts
Configure Next.js image hostname dynamically                         

next.config.ts

  • Updated remote image pattern hostname to use process.env.R2_PUBLIC_URL
  • Added URL parsing to extract hostname by removing protocol prefix
  • Provides fallback empty string if environment variable is not set
+1/-1     
Documentation
.env.example
Document R2_PUBLIC_URL environment variable                           

.env.example

  • Added R2_PUBLIC_URL environment variable to example configuration
  • Allows users to specify their custom Cloudflare R2 bucket public URL
+1/-0     

Summary by CodeRabbit

  • Chores
    • Updated application configuration to support environment-driven settings for image hosting, allowing for greater deployment flexibility without code changes.

@vercel
Copy link

vercel bot commented Oct 20, 2025

@vedantterse is attempting to deploy a commit to the Goshen Labs Team on Vercel.

A member of the Team first needs to authorize it.

@qodo-merge-pro
Copy link

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🟡
🎫 #57
🟢 Replace hardcoded Cloudflare R2 public URL in code with a configurable environment
variable.
Ensure upload-image.ts constructs public URLs using the environment variable.
Update next.config.ts to use the environment variable for image remotePatterns/hostname.
Add R2_PUBLIC_URL to .env.example so users can configure their bucket URL.
Make setup work out of the box for custom R2 buckets without manual code changes.
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
No custom compliance provided

Follow the guide to enable custom compliance check.

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@coderabbitai
Copy link

coderabbitai bot commented Oct 20, 2025

Walkthrough

The changes remove hardcoded Cloudflare R2 public URLs by introducing an R2_PUBLIC_URL environment variable. Three files were modified to reference this variable: .env.example documents the new variable, lib/upload-image.ts uses it for constructing image URLs, and next.config.ts derives the remote pattern hostname from it.

Changes

Cohort / File(s) Summary
Environment Configuration
.env.example
Added R2_PUBLIC_URL environment variable placeholder
Upload Logic
lib/upload-image.ts
Replaced hardcoded public URL (pub-6f0cf05705c7412b93a792350f3b3aa5.r2.dev) with environment-driven URL construction
Next.js Configuration
next.config.ts
Updated remotePatterns hostname to derive from R2_PUBLIC_URL with protocol stripping and empty-string fallback

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

The changes follow a consistent, homogeneous pattern: replacing hardcoded URLs with environment variables across three configuration/integration points. Logic is straightforward with minimal complexity.

Poem

🐰 The URLs once locked, now dance and sway,
With R2_PUBLIC_URL leading the way!
No more hardcoding, flexibility springs—
Each bucket blooms with environmental wings ✨

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "fix: remove hardcoded R2 public URL and use env variable instead" clearly and specifically summarizes the primary change in the changeset. The title accurately reflects that hardcoded R2 URLs are being removed and replaced with environment variable references across multiple files. The title is concise, avoids vague terminology, and would help a teammate scanning the git history quickly understand the core purpose of the change.
Linked Issues Check ✅ Passed The pull request successfully addresses all primary coding objectives from issue #57. The changes include adding the R2_PUBLIC_URL environment variable to .env.example, updating lib/upload-image.ts to use the environment variable instead of the hardcoded URL, and modifying next.config.ts to dynamically read the hostname from the environment variable with an appropriate fallback. These modifications directly fulfill the requirement to make the R2 public URL configurable and improve out-of-the-box compatibility with custom R2 bucket configurations.
Out of Scope Changes Check ✅ Passed All changes in the pull request are directly related to the stated objective of removing hardcoded R2 public URLs and making them environment-driven. The modifications to .env.example, lib/upload-image.ts, and next.config.ts are all necessary and focused on enabling configurable R2 bucket support. No unrelated or tangential changes have been introduced outside the scope of the linked issue.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-merge-pro
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Robustly parse hostname from URL

Replace the regex-based hostname extraction with the URL constructor for
robustness. Additionally, throw an error if the R2_PUBLIC_URL environment
variable is not set to prevent build errors.

next.config.ts [13]

-hostname: process.env.R2_PUBLIC_URL?.replace(/^https?:\/\//, "") || "",
+hostname: (() => {
+  if (!process.env.R2_PUBLIC_URL) {
+    // Returning an empty string can cause obscure errors.
+    // It's better to fail fast if the required env var is missing.
+    throw new Error(
+      "R2_PUBLIC_URL environment variable is not set. This is required for Next.js Image Optimization."
+    );
+  }
+  try {
+    return new URL(process.env.R2_PUBLIC_URL).hostname;
+  } catch (e) {
+    throw new Error(`Invalid R2_PUBLIC_URL: ${process.env.R2_PUBLIC_URL}`);
+  }
+})(),
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies that the regex-based hostname extraction is fragile and will fail with URLs containing paths, proposing a much more robust solution using the native URL constructor.

Medium
Validate environment variable before use

Validate that the R2_PUBLIC_URL environment variable is defined before using it.
If it is missing, throw an error to prevent generating invalid URLs and to flag
the configuration issue.

lib/upload-image.ts [26-27]

+if (!process.env.R2_PUBLIC_URL) {
+  throw new Error("Missing required environment variable: R2_PUBLIC_URL");
+}
 const publicUrl = `${process.env.R2_PUBLIC_URL}/${key}`;
 return publicUrl;
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that a missing R2_PUBLIC_URL environment variable would lead to broken image URLs and proposes a robust solution by validating its existence, which is a good practice.

Medium
  • More

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
.env.example (1)

12-12: Document the expected format for R2_PUBLIC_URL.

The environment variable lacks documentation about its expected format. Users need to know whether to include the protocol (https://) and whether a trailing slash should be present.

Apply this diff to add helpful documentation:

 # Cloudflare R2
 R2_UPLOAD_IMAGE_ACCESS_KEY_ID=
 R2_UPLOAD_IMAGE_SECRET_ACCESS_KEY=
 CLOUDFLARE_ACCOUNT_ID=
 R2_UPLOAD_IMAGE_BUCKET_NAME=images
-R2_PUBLIC_URL=
+# R2 bucket public URL (include protocol, no trailing slash)
+# Example: https://pub-xxxxxx.r2.dev
+R2_PUBLIC_URL=

Note: The static analysis tool suggests reordering this key to appear before R2_UPLOAD_IMAGE_ACCESS_KEY_ID for alphabetical consistency, but this is optional.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b80fdf3 and 7b985c8.

📒 Files selected for processing (3)
  • .env.example (1 hunks)
  • lib/upload-image.ts (1 hunks)
  • next.config.ts (1 hunks)
🧰 Additional context used
🪛 dotenv-linter (4.0.0)
.env.example

[warning] 12-12: [UnorderedKey] The R2_PUBLIC_URL key should go before the R2_UPLOAD_IMAGE_ACCESS_KEY_ID key

(UnorderedKey)

);

const publicUrl = `https://pub-6f0cf05705c7412b93a792350f3b3aa5.r2.dev/${key}`;
const publicUrl = `${process.env.R2_PUBLIC_URL}/${key}`;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add validation and normalization for R2_PUBLIC_URL.

The code doesn't validate that R2_PUBLIC_URL is defined, which will result in URLs like "undefined/image.png" if the environment variable is missing. Additionally, if the URL has a trailing slash, the result will be malformed (e.g., "https://example.com//key").

Apply this diff to add validation and handle trailing slashes:

-  const publicUrl = `${process.env.R2_PUBLIC_URL}/${key}`;
+  const baseUrl = process.env.R2_PUBLIC_URL;
+  if (!baseUrl) {
+    throw new Error("R2_PUBLIC_URL environment variable is not configured");
+  }
+  const normalizedBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
+  const publicUrl = `${normalizedBase}/${key}`;
   return publicUrl;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const publicUrl = `${process.env.R2_PUBLIC_URL}/${key}`;
const baseUrl = process.env.R2_PUBLIC_URL;
if (!baseUrl) {
throw new Error("R2_PUBLIC_URL environment variable is not configured");
}
const normalizedBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
const publicUrl = `${normalizedBase}/${key}`;
return publicUrl;
🤖 Prompt for AI Agents
In lib/upload-image.ts around line 26, the code builds publicUrl directly from
process.env.R2_PUBLIC_URL which may be undefined or contain a trailing slash;
update the code to first validate that process.env.R2_PUBLIC_URL is defined
(throw a clear error or return a failure if not), then normalize the value by
trimming whitespace and removing any trailing slash (or use the URL/URL
constructor to resolve paths) before concatenating the key so you never produce
"undefined/..." or double slashes; ensure the final join guarantees exactly one
slash between base URL and key.

{
protocol: "https",
hostname: "pub-6f0cf05705c7412b93a792350f3b3aa5.r2.dev",
hostname: process.env.R2_PUBLIC_URL?.replace(/^https?:\/\//, "") || "",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Improve hostname extraction and handle missing R2_PUBLIC_URL.

The current implementation has several issues:

  1. The empty string fallback will create an invalid remotePatterns entry when R2_PUBLIC_URL is not set, potentially causing Next.js configuration errors.
  2. The regex approach doesn't handle URLs with path segments (e.g., https://example.com/bucket → invalid hostname example.com/bucket).
  3. If the URL lacks a protocol, the regex has no effect, which could lead to an invalid hostname.

Apply this diff to properly parse the hostname using the URL API:

+const getR2Hostname = () => {
+  const url = process.env.R2_PUBLIC_URL;
+  if (!url) {
+    console.warn("R2_PUBLIC_URL is not configured. R2 image optimization will not work.");
+    return undefined;
+  }
+  try {
+    // Ensure URL has protocol for parsing
+    const fullUrl = url.startsWith('http') ? url : `https://${url}`;
+    return new URL(fullUrl).hostname;
+  } catch (error) {
+    console.error("Invalid R2_PUBLIC_URL format:", url);
+    return undefined;
+  }
+};
+
 const nextConfig: NextConfig = {
   /* config options here */
   reactStrictMode: false,
   typescript: {
     ignoreBuildErrors: true,
   },
   images: {
-    remotePatterns: [
+    remotePatterns: [
+      ...(getR2Hostname() ? [{
-      {
         protocol: "https",
-        hostname: process.env.R2_PUBLIC_URL?.replace(/^https?:\/\//, "") || "",
-      },
+        hostname: getR2Hostname()!,
+      }] : []),
       {
         protocol: "https",
         hostname: "jdj14ctwppwprnqu.public.blob.vercel-storage.com",

This approach:

  • Uses the URL API for robust hostname extraction
  • Handles missing protocol gracefully
  • Excludes the pattern entirely if R2_PUBLIC_URL is not configured (rather than using an empty string)
  • Provides helpful warnings in the console

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In next.config.ts around line 13, the hostname extraction from R2_PUBLIC_URL is
brittle and can produce invalid remotePatterns entries; update the code to:
check if process.env.R2_PUBLIC_URL is set, if not omit the R2_REMOTE pattern
entirely and emit a console.warn; if set, ensure the value has a protocol
(prepend "https://" if missing), parse it with the URL constructor to extract
only the hostname (no path or port), and use that hostname in remotePatterns so
Next.js never receives an empty or path-containing host; also catch and warn on
URL parsing errors and fall back to omitting the pattern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hardcoded Cloudflare R2 public URL prevents custom bucket configuration

1 participant