TidyURLs
Go to Tools
BLOG
The TidyURLsJournal

Practical guides, tutorials, and insights about URLs, SEO, web development, and online marketing. Learn, troubleshoot, and get the most of the web.

Back to the Journal
TidyURLs Journal

Why Your Website Works Locally but Not in Production: A Debugging Checklist

Practical insights, clear explanations, and useful ideas for understanding the web.

October 25, 20269 min read6 topics
Why Your Website Works Locally but Not in Production: A Debugging Checklist
Explore the details
#deployment#debugging#web development#DNS#TLS#production
October 25, 20269 min read

A site that runs perfectly on your laptop can still fail after deployment. The production environment may use different configuration, build commands, file permissions, network settings, or caching rules—and its error messages may not appear in the browser at all. The result can be anything from a blank page to a failed API request or a domain that will not load.

This guide walks through a fictional debugging case and a practical checklist for when a website works locally but not in production. It covers environment variables, build errors, runtime errors, DNS, TLS, caching, permissions, and production logs.

Key takeaways

  • Compare the deployed environment with the working local setup instead of assuming the code is the only difference.
  • Check the production build and server logs before making speculative code changes.
  • Test DNS, TLS, and HTTP responses separately; each can fail for different reasons.
  • Treat frontend configuration, secrets, and server-side settings differently.
  • Make one change at a time and verify the result with a repeatable request.

An illustrative debugging case

Imagine a developer deploys a small web app. The home page loads on their computer, but the production URL shows an error, and the page's data does not appear. This is an illustrative scenario, not a report of a specific incident.

Rather than changing several things at once, the developer divides the problem into layers: does the domain resolve, can a secure connection be established, does the server return an HTTP response, does the application start, and can the browser load the required assets and data? This sequence narrows the search without treating every symptom as the same failure.

1. Check environment variables and configuration

Local development often relies on a local .env file, shell settings, or a development-only configuration. Those values are not necessarily available to a deployed application. A missing API base URL, database connection setting, or feature flag can cause a failure even when the code is unchanged.

Check the following:

  • Confirm that each required variable is configured in the deployment environment, using the exact name expected by the application.
  • Check whether the hosting platform separates preview, staging, and production settings. The deployment may be using a different environment than expected.
  • Verify whether a variable is read at build time or at runtime. Some frontend frameworks embed public configuration into generated assets during the build, so changing a hosting setting later may require a new build.
  • Do not place credentials or private keys in browser-exposed variables. Anything included in client-side JavaScript should be treated as public.
  • Compare configuration names and non-sensitive values carefully. Do not copy production secrets into logs, screenshots, or issue reports.

For diagnosis, report whether a variable is set without printing its value. For example, server-side Node.js code can check presence like this:

const required = ["API_BASE_URL"];

for (const name of required) {
  if (!process.env[name]) {
    console.error(`Missing required environment variable: ${name}`);
    process.exitCode = 1;
  }
}

This checks only whether a value exists; it does not validate its format, connectivity, or permissions. Adapt the variable name and startup behavior to your application and deployment platform.

2. Inspect build errors and deployment output

A development server and a production build do not always follow the same path. Production builds can expose type errors, missing imports, case-sensitive file paths, unsupported runtime features, or assumptions about files that are present locally but absent from the repository.

Review the full build output, including the command that ran and its exit code. Confirm that the deployment is building the intended branch and commit, using the expected package manager and lockfile, and running the correct build command. If a module works on a case-insensitive local filesystem but not on a case-sensitive build environment, check that import capitalization exactly matches the filename.

When you cannot reproduce the failure locally, try the documented production build command in a clean checkout or container with the same runtime version and dependency lockfile. This can help identify differences, but it does not guarantee the deployed environment is identical.

3. Separate browser errors from server runtime errors

A successful build does not prove that the application works after it starts. Runtime failures may occur during startup, on a particular route, or only when a request reaches a database or external service.

Open the browser's developer tools and inspect both the Console and Network panels. Look for failed JavaScript files, blocked requests, incorrect API URLs, CORS errors, and responses with unexpected status codes. Then check the server or function logs for exceptions and startup failures. A browser message may describe the visible symptom, while the server log contains the underlying cause.

If the page responds but an API call fails, test that endpoint independently and compare the request URL, method, headers, and response with the working local case. Avoid assuming a browser-side error is caused by CORS: first confirm that the endpoint exists and is reachable, and inspect the actual response.

4. Verify DNS, TLS, and HTTP responses

A deployment can be healthy while its domain points somewhere else, or the domain can resolve while the secure connection is misconfigured. Check these layers in order:

  1. DNS: Confirm that the domain's records point to the destination specified by the hosting provider. DNS changes may take time to become visible across resolvers, so compare results from more than one network or resolver when appropriate.
  2. TLS: Check that the browser connects over HTTPS without a certificate warning. Confirm that the certificate covers the exact hostname, including any www or subdomain variation you use.
  3. HTTP: Once DNS and TLS work, inspect the response status and redirect behavior. A 404 can indicate a route or deployment issue; a 5xx commonly signals a server-side failure, though the status alone does not identify its cause.

You can inspect a response from a terminal with curl:

curl -sS -D - -o /dev/null https://example.com/

Replace example.com with a domain you own or are authorized to test. The command prints response headers without printing the response body. A redirect is not necessarily an error, so check its Location header and test the final destination too. A status-checking tool such as check an HTTP response can help inspect a URL's HTTP response, but it cannot diagnose every DNS, TLS, application, or hosting configuration problem.

5. Rule out stale or incorrect caching

A deployment may be correct while a browser, CDN, service worker, or intermediary cache continues to serve older assets. This can look like a broken release when the server is actually returning a previous version of a file.

Compare the response headers and asset names from a normal browser session with a private window or a fresh request. If the application uses a service worker, check whether it is serving cached content. Review the hosting or CDN cache configuration and follow its documented process for invalidating cached assets. Avoid repeatedly purging caches without checking which layer is stale; that can hide the cause and make the issue harder to reproduce.

6. Check file and resource permissions

Local development may run with access that the deployed process does not have. A production application can fail when it cannot read a required file, write to a directory, access a mounted resource, or connect to a service under its assigned identity.

Check the exact file or resource named in the logs. Confirm that it is included in the deployment, that its path and capitalization match, and that the application runs with the permissions it needs—but no broader access than necessary. Do not solve permission errors by granting unrestricted access. If the application writes files, verify that the target directory is intended to be writable in the hosting environment; some platforms use temporary or read-only filesystems.

7. Use production logs to narrow the failure

Logs are most useful when they include enough context to connect an error to a request, release, or startup attempt without exposing sensitive information. Check the logs from the same deployment and time period as the failed request. Look for startup errors, uncaught exceptions, unavailable dependencies, and configuration validation messages.

If logs are empty, confirm that you are viewing the correct service, region, environment, and time window. Some platforms separate build logs from runtime logs, and some applications need explicit logging configuration. Do not log passwords, access tokens, private keys, or full request data that may contain personal information.

A repeatable debugging workflow

Use this sequence to keep the investigation focused:

  1. Record the failing URL, approximate time, browser, and exact visible error. Note whether the problem affects every route or only one.
  2. Check whether the domain resolves and whether HTTPS connects without a certificate warning.
  3. Inspect the HTTP response and redirects. If the server responds, note the status code and relevant headers.
  4. Check the browser Console and Network panels for failed assets or API calls.
  5. Review the deployment's build output and runtime logs for the same release and time period.
  6. Compare production configuration with the working environment, checking variable names and presence without exposing secret values.
  7. Verify file paths, runtime assumptions, and resource permissions.
  8. Consider stale browser, service worker, or CDN content only after checking what the server currently returns.
  9. Change one likely cause at a time, redeploy if required, and repeat the same checks.

Common mistakes

  • Changing many settings at once: This makes it difficult to tell which change affected the outcome. Keep a short record of each test and result.
  • Treating every failure as an application bug: A domain, certificate, cache, or deployment configuration can fail before application code runs.
  • Checking only the local development server: Test the production build and the deployed URL, since the startup path and environment may differ.
  • Assuming a status code explains the root cause: A response code is evidence, not a full diagnosis. Correlate it with logs and the failing request.
  • Printing secrets while debugging: Confirm configuration safely; redact sensitive values from logs and shared reports.
  • Making broad permission changes: Grant only the access the application needs and investigate the specific resource that failed.

Conclusion

When a website works locally but not in production, the fastest route to a fix is usually a disciplined comparison of environments and a layer-by-layer check of the deployed request. Start with DNS and TLS, inspect HTTP responses, then follow the evidence through browser errors, build output, configuration, permissions, caching, and production logs. A repeatable checklist helps you find the relevant difference without masking the original problem.