How to encode a string in base64 in JavaScript
Encoding strings to base64 is essential for data transmission, API authentication, image data handling, and implementing features like email attachments or secure data storage in JavaScript applications.
With over 25 years of experience in software development and as the creator of CoreUI, I’ve implemented base64 encoding in components like file upload systems, API integrations, and data export features where converting text to a safe, transmittable format is crucial for reliable data handling.
From my expertise, the most direct and browser-native solution is using the built-in btoa() function, which provides standard base64 encoding.
This approach is efficient, widely supported, and specifically designed for binary-to-ASCII conversion in web environments.
Use the btoa() function to encode a string into base64 format.
const text = 'Hello World'
const encoded = btoa(text)
// Result: 'SGVsbG8gV29ybGQ='
The btoa() function (binary-to-ASCII) converts a string into its base64 representation, creating a safe ASCII string that can be transmitted over text-based protocols. In this example, btoa('Hello World') produces 'SGVsbG8gV29ybGQ=', which is the base64-encoded version. The function only works with strings containing characters in the 0-255 range (Latin-1). For Unicode strings containing emoji, CJK, or accented characters, you need the TextEncoder approach described in Section 2.
1. Encoding ASCII Strings and JSON
For simple ASCII text, btoa() works directly. A common pattern is encoding JSON payloads for transmission in URLs or HTTP headers.
// Basic text encoding
console.log(btoa('Hello World'))
// Result: 'SGVsbG8gV29ybGQ='
// Encode numbers as strings
console.log(btoa('1234567890'))
// Result: 'MTIzNDU2Nzg5MA=='
// Encode JSON data for API transmission
const userData = { user: 'admin', role: 'editor' }
const jsonEncoded = btoa(JSON.stringify(userData))
console.log(jsonEncoded)
// Result: 'eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoiZWRpdG9yIn0='
// Encode for Basic Authentication header
const username = 'admin'
const password = 'secret123'
const authHeader = 'Basic ' + btoa(`${username}:${password}`)
console.log(authHeader)
// Result: 'Basic YWRtaW46c2VjcmV0MTIz'
// URL-safe base64 (replace + and / with - and _)
const standard = btoa('Hello World?')
const urlSafe = standard.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
console.log(urlSafe)
// Result: 'SGVsbG8gV29ybGQ_'
URL-safe base64 replaces + with - and / with _ to avoid conflicts in URLs and query parameters. The trailing = padding can optionally be removed since the decoder can infer it from the string length. For the reverse operation, see how to decode a base64 string in JavaScript.
2. Encoding Unicode Strings
The btoa() function throws a DOMException when the string contains characters outside the Latin-1 range (code points above 255). Use TextEncoder to handle Unicode correctly.
// btoa() fails with Unicode
try {
btoa('café') // é is within Latin-1, this works
console.log(btoa('café'))
// Result: 'Y2Fmw6k=' — wait, this actually throws in some cases
} catch (error) {
console.log('Failed:', error.message)
}
// btoa() definitely fails with characters above 255
try {
btoa('你好')
} catch (error) {
console.log(error.message)
// 'The string to be encoded contains characters outside of the
// Latin1 range.'
}
// Modern approach: TextEncoder (recommended)
const encodeBase64Unicode = (text) => {
const bytes = new TextEncoder().encode(text)
const binaryString = Array.from(bytes, byte => String.fromCharCode(byte)).join('')
return btoa(binaryString)
}
console.log(encodeBase64Unicode('café'))
// Result: 'Y2Fmw6k='
console.log(encodeBase64Unicode('你好'))
// Result: '5L2g5aW9'
console.log(encodeBase64Unicode('Hello 😀'))
// Result: 'SGVsbG8g8J+YgA=='
// Legacy approach (still works but harder to read)
const encodeBase64Legacy = (text) => {
return btoa(
encodeURIComponent(text).replace(
/%([0-9A-F]{2})/g,
(_, p1) => String.fromCharCode(parseInt(p1, 16))
)
)
}
console.log(encodeBase64Legacy('你好'))
// Result: '5L2g5aW9'
The TextEncoder approach converts the string to UTF-8 bytes first, then converts each byte to a Latin-1 character that btoa() can handle. This is the modern, clean way to encode Unicode strings and pairs perfectly with the TextDecoder approach for decoding.
3. Creating Data URIs
Data URIs embed file content directly in HTML or CSS using base64 encoding. This eliminates HTTP requests for small assets like icons and thumbnails.
// Create a data URI from text
const createTextDataUri = (text, mimeType = 'text/plain') => {
return `data:${mimeType};base64,${btoa(text)}`
}
console.log(createTextDataUri('Hello World'))
// Result: 'data:text/plain;base64,SGVsbG8gV29ybGQ='
// Create SVG data URI (useful for inline backgrounds)
const svgContent = '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><circle cx="50" cy="50" r="40" fill="blue"/></svg>'
const svgDataUri = createTextDataUri(svgContent, 'image/svg+xml')
// Use in CSS: background-image: url('data:image/svg+xml;base64,...')
// Create data URI from a File/Blob
const fileToBase64 = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = () => resolve(reader.result)
reader.onerror = reject
reader.readAsDataURL(file)
})
}
// Usage with file input
// const file = document.querySelector('input[type="file"]').files[0]
// const dataUri = await fileToBase64(file)
// console.log(dataUri) // 'data:image/png;base64,iVBORw0KGgo...'
// Convert canvas to base64
// const canvas = document.querySelector('canvas')
// const base64Image = canvas.toDataURL('image/png')
Data URIs are ideal for small files (under ~10KB). For larger files, separate HTTP requests with caching are more efficient. The FileReader approach is commonly used with CoreUI form file inputs to preview uploaded images before submission.
4. Encoding for API Authentication
Base64 encoding is used in several authentication schemes, most notably HTTP Basic Authentication and API key encoding.
// HTTP Basic Authentication
const createBasicAuth = (username, password) => {
return 'Basic ' + btoa(`${username}:${password}`)
}
const headers = {
'Authorization': createBasicAuth('api_user', 'api_key_123'),
'Content-Type': 'application/json'
}
console.log(headers.Authorization)
// Result: 'Basic YXBpX3VzZXI6YXBpX2tleV8xMjM='
// Encode API credentials for storage
const encodeCredentials = (config) => {
return btoa(JSON.stringify(config))
}
const decodeCredentials = (encoded) => {
return JSON.parse(atob(encoded))
}
const apiConfig = {
endpoint: 'https://api.example.com',
key: 'sk_live_abc123',
version: 'v2'
}
const encoded = encodeCredentials(apiConfig)
console.log(encoded)
// Result: base64 string
const decoded = decodeCredentials(encoded)
console.log(decoded.endpoint)
// Result: 'https://api.example.com'
// Create a simple obfuscated config (NOT encryption!)
const obfuscate = (data) => btoa(btoa(JSON.stringify(data)))
const deobfuscate = (str) => JSON.parse(atob(atob(str)))
Important: Base64 encoding is not encryption. It provides no security — anyone can decode it. Never use base64 as a way to “hide” sensitive data. For actual security, use proper encryption. Base64 is purely a data format for safe text transmission.
5. Encoding Binary Data from ArrayBuffer
When working with binary data from fetch(), WebSocket, or crypto APIs, you often need to convert ArrayBuffer or Uint8Array to base64.
// Convert ArrayBuffer to base64
const arrayBufferToBase64 = (buffer) => {
const bytes = new Uint8Array(buffer)
const binaryString = Array.from(bytes, byte => String.fromCharCode(byte)).join('')
return btoa(binaryString)
}
// Encode a hash as base64
const hashToBase64 = async (message) => {
const encoder = new TextEncoder()
const data = encoder.encode(message)
const hashBuffer = await crypto.subtle.digest('SHA-256', data)
return arrayBufferToBase64(hashBuffer)
}
// const hash = await hashToBase64('Hello World')
// console.log(hash) // base64-encoded SHA-256 hash
// Convert Uint8Array to base64
const uint8ToBase64 = (uint8Array) => {
const binaryString = Array.from(uint8Array, byte => String.fromCharCode(byte)).join('')
return btoa(binaryString)
}
const bytes = new Uint8Array([72, 101, 108, 108, 111])
console.log(uint8ToBase64(bytes))
// Result: 'SGVsbG8=' (base64 of 'Hello')
// Encode random bytes (useful for tokens/nonces)
const randomBase64 = (length) => {
const bytes = new Uint8Array(length)
crypto.getRandomValues(bytes)
return arrayBufferToBase64(bytes.buffer)
}
console.log(randomBase64(16))
// Result: random 24-character base64 string
The Array.from(bytes, byte => String.fromCharCode(byte)).join('') pattern converts each byte to its Latin-1 character equivalent, creating a binary string that btoa() can process. This is the standard way to bridge between typed arrays and base64 in browser JavaScript.
6. Encoding in Node.js with Buffer
In Node.js, the Buffer class provides a cleaner API for base64 encoding. It handles Unicode automatically without the workarounds needed for btoa().
// Node.js: Buffer handles everything
const encoded = Buffer.from('Hello World').toString('base64')
// Result: 'SGVsbG8gV29ybGQ='
// Unicode works directly
const unicodeEncoded = Buffer.from('café 你好 😀').toString('base64')
// Result: 'Y2Fmw6kg5L2g5aW9IPCfmIA='
// Encode from different input encodings
const hexEncoded = Buffer.from('48656c6c6f', 'hex').toString('base64')
// Result: 'SGVsbG8='
// Isomorphic encode function (browser + Node.js)
const encodeBase64 = (text) => {
if (typeof Buffer !== 'undefined') {
// Node.js
return Buffer.from(text).toString('base64')
}
// Browser — handle Unicode via TextEncoder
const bytes = new TextEncoder().encode(text)
const binaryString = Array.from(bytes, b => String.fromCharCode(b)).join('')
return btoa(binaryString)
}
console.log(encodeBase64('Hello 😀'))
// Result: 'SGVsbG8g8J+YgA==' (in both environments)
// URL-safe base64 in Node.js
const urlSafe = Buffer.from('Hello World').toString('base64url')
// Result: 'SGVsbG8gV29ybGQ' (no padding, URL-safe chars)
Node.js 16+ also supports btoa() globally, but Buffer remains the idiomatic choice for server-side code because it handles Unicode natively and supports URL-safe base64 via 'base64url' encoding. The isomorphic function works in both environments, making it ideal for shared libraries.
Best Practice Note:
For ASCII-only content, btoa() works directly. For Unicode content, always use the TextEncoder approach — convert to UTF-8 bytes first, then to a binary string for btoa(). Remember that base64 encoding increases data size by approximately 33%, so avoid encoding large files inline. In Node.js, prefer Buffer.from(str).toString('base64') over btoa(). For the decoding counterpart, see how to decode a base64 string in JavaScript. For related string conversion operations, see how to convert a string to an array in JavaScript.



