October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
Amazon S3

How to Save a PDF Online and Get a URL in Node.js

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To save a PDF online from Node.js, upload its bytes to an object-storage service such as Amazon S3, Supabase Storage, or Firebase Cloud Storage, then return a URL that matches the document’s intended access level. A public URL is suitable only for a PDF meant to be openly available; for private documents, use authentication or an expiring signed URL. Uploading the file alone does not make it public.

Choose who should be able to open the PDF

There are two separate decisions: where the PDF is stored and how a reader is authorized to retrieve it. A URL may be public to anyone who has it, or it may require authentication or expire after a configured period. Treat a shareable link as a bearer credential whenever possession of the link is enough to read the file.

Access model What the URL does Use it when
Public object URL Anyone who can obtain the URL can request the object. The PDF is intended for unrestricted distribution.
Authenticated access The application or storage service checks a user’s identity and permissions. Access should depend on an account or application policy.
Signed URL A time-limited URL grants access to a specific object, subject to provider rules and the credentials that created it. You need to share a private PDF temporarily without making the bucket public.

Upload permission and download permission are different. A presigned URL that lets a browser upload a PDF does not automatically create the URL a recipient will use to read it.

Use Supabase Storage from Node.js

The following server-side example uses the Supabase JavaScript client to upload a PDF to a private bucket and return a signed download URL. Create the bucket in your Supabase project first. Keep the service-role key in a server-side environment variable; never send it to browser code. Install the current client package with npm install @supabase/supabase-js.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Set SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY in the Node.js server environment. Create a private bucket named documents, or change the bucket name in the example. This CommonJS file expects Node.js with global fetch available, as in current Node.js releases.

const { createClient } = require('@supabase/supabase-js');
const fs = require('node:fs/promises');
const path = require('node:path');
const { randomUUID } = require('node:crypto');

const supabase = createClient(
  process.env.SUPABASE_URL,
  process.env.SUPABASE_SERVICE_ROLE_KEY
);

async function uploadPdf(localPath) {
  const bytes = await fs.readFile(localPath);
  const objectPath = `pdfs/${randomUUID()}.pdf`;

  const { error: uploadError } = await supabase.storage
    .from('documents')
    .upload(objectPath, bytes, {
      contentType: 'application/pdf',
      upsert: false
    });

  if (uploadError) throw uploadError;

  const expiresInSeconds = 60 * 60;
  const { data, error: urlError } = await supabase.storage
    .from('documents')
    .createSignedUrl(objectPath, expiresInSeconds);

  if (urlError) throw urlError;
  return { path: objectPath, url: data.signedUrl };
}

uploadPdf(path.join(__dirname, 'report.pdf'))
  .then(({ path, url }) => {
    console.log(JSON.stringify({ path, url }, null, 2));
  })
  .catch((error) => {
    console.error('PDF upload failed:', error.message);
    process.exitCode = 1;
  });

The function reads the PDF, assigns a non-guessable object name, uploads with the PDF content type, and only then creates and returns a signed URL. The requested one-hour lifetime is an application choice in this example; Supabase’s signed-upload capability is a separate mechanism and its documentation states that signed upload URLs are valid for two hours. Check current provider documentation for the exact API and security behavior before deploying.

For a public PDF

If the file is meant to be public, configure a public bucket and use the client’s getPublicUrl(objectPath) method after upload. Supabase documents that public buckets expose public object URLs. Do not use a public bucket merely to make URL generation simpler: it changes the access model for the bucket’s objects.

For private PDFs

Keep the bucket private and create a signed URL only after the application has decided that the requester may access that particular PDF. Store the object path in your database and associate it with the relevant user or record. A signed URL is a convenient delivery mechanism, not a substitute for your application’s authorization check.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Build the upload flow safely

  1. Receive or create the PDF. Use the resulting buffer or stream in your Node.js server. If it comes from a user, enforce an upload-size limit and validate that it is a PDF rather than trusting the filename or browser-supplied MIME type.
  2. Choose a bucket and object key. Use a private bucket by default for non-public documents. Generate unpredictable keys, such as a UUID, rather than placing user filenames or sensitive information in a public path.
  3. Upload with narrow credentials. Run storage operations on the server with credentials scoped to the required bucket and actions. For direct browser uploads, issue a constrained upload capability for an application-approved path instead of exposing storage credentials.
  4. Choose read authorization separately. Return a public object URL only for intentionally public files. Otherwise, require authenticated access or mint an expiring signed URL after authorization.
  5. Return the URL only after success. Check the upload result before creating a link. If upload fails, return an appropriate error rather than a URL that points to a missing object.

How the main storage providers handle PDF URLs

Provider Public or download URL Private or temporary access Important qualification
Amazon S3 Objects can be exposed according to bucket and object permissions. Presigned URLs can authorize time-limited reads; presigned URLs can also authorize an upload of a specific object. Effective validity is limited by both the URL expiration and the credentials used to create it. Keep credentials server-side and grant only required permissions.
Supabase Storage getPublicUrl provides a URL for assets in a public bucket. createSignedUrl(path, expiresIn) creates expiring access for a private object. Signed upload URLs are a distinct upload capability. Supabase documents signed upload URLs as valid for two hours; that duration describes upload capability, not a general download-link lifetime.
Firebase Cloud Storage Upload documentation shows retrieving a download URL. The Admin SDK documents a non-expiring shareable download URL. Bucket operations require authentication by default unless security rules are changed; access can be controlled through those rules and application design. Anyone possessing the documented shareable download URL can access the file, so treat it as a bearer link.

Use the storage system already provisioned for your application where practical, then verify its current SDK, IAM or security-rule model, quotas, pricing, and region. The provider-specific URL behavior above is not a price or performance comparison.

Expiration, revocation, and direct uploads

Signed URL lifetime

Set an expiry long enough for the recipient’s task, but no longer than necessary. With S3, a requested expiry cannot outlive the credentials that generated the URL. A link created with short-lived credentials may stop working before its configured expiration. Supabase’s createSignedUrl accepts an expiration duration for read access; signed upload URLs are separate and documented as valid for two hours. Firebase’s documented shareable download URL is non-expiring, so do not treat it like a short-lived signed link.

Revocation

Do not assume that deleting a URL from your application revokes the storage capability itself. Revocation behavior depends on the provider and the access mechanism. For sensitive material, prefer an access path your application can authorize on each request, and consult the provider’s current documentation on invalidating credentials, changing object permissions, or replacing the object.

Browser-to-storage uploads

For large PDFs, an application may let the browser upload directly to storage using a scoped, temporary upload URL. The server should decide the allowed bucket and object path, impose size and type checks, and retain the authority to issue or deny that capability. Do not confuse this upload URL with the reader-facing download URL; create or return the latter only after the upload has completed and the application has applied its access policy.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Troubleshooting common failures

  • The upload returns an authorization error: Verify the server environment variables, bucket name, and permissions for the operation. Do not fix this by exposing a service key in client code or making a private bucket public.
  • The returned link gives a not-found response: Confirm the upload succeeded and that the URL references the same bucket and exact object path. Generate the link after the upload has completed.
  • A private object URL is inaccessible: A plain object URL does not grant private access. Authenticate the request or create a signed read URL after checking the requester’s permissions.
  • A previously working signed link has expired: Create a new link after rechecking authorization. For S3, also consider whether the credentials used to sign it expired earlier than the configured link duration.
  • A Firebase download URL is more broadly accessible than expected: Treat it as a bearer link and avoid distributing it for sensitive files. Review the bucket’s security rules and how the URL is delivered.
  • The file opens with the wrong handling or type: Set the object content type to application/pdf during upload and verify the stored metadata.

Performance and cost decisions

PDF storage and transfer costs, request limits, regional availability, and latency depend on the selected provider, account, region, and usage. Check current provider pricing and quotas rather than assuming that object storage or signed-link generation is free. For performance, avoid loading an entire large PDF into memory when your framework and provider SDK support streaming; also consider direct uploads for large files, while keeping validation and authorization in the server-controlled flow.

Use a storage region appropriate to your application and users, and test the complete path—including upload, URL generation, and recipient access—under the permissions you intend to deploy. A link that works for an administrator may fail for an ordinary user if the application’s authorization path differs.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If the PDF’s source is a web page that you need to capture before saving or sharing it, ScreenshotNeo can return a screenshot or PDF from one GET request. For this article’s Node.js task, it is a companion for generating a PDF from a page; it is not a replacement for uploading that PDF to object storage or choosing who can read it. The call below requests a PDF capture from a URL:

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com',
  format: 'pdf'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo request failed: ${res.status}`);
const pdf = Buffer.from(await res.arrayBuffer());
await require('node:fs/promises').writeFile('page.pdf', pdf);

See the ScreenshotNeo API documentation for request options. ScreenshotNeo removes cookie banners, popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed; an MCP server lets AI agents take screenshots; and 1,000 screenshots per month are free with no card, with paid plans starting at $5 for 3,000. Sign up for ScreenshotNeo free.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Does uploading a PDF automatically create a public URL?

No. Uploading stores the object; its bucket permissions and the URL or authorization method determine who can retrieve it.

Can I use a signed upload URL as the download link?

No. Upload authorization and reader access are separate. After upload, create or return a URL designed for reading the object.

Should I make a bucket public to share one PDF?

Only if the PDF is intended for public access under that bucket’s policy. For a private document, use authenticated access or a suitable signed link.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.