URLs don't have native array support, so different systems use different conventions. Understanding these formats helps you work with various APIs and frameworks.
Key Takeaways
- 1Repeated keys: ?tag=a&tag=b (most common)
- 2Bracket notation: ?tags[]=a&tags[]=b (PHP/Rails style)
- 3Comma-separated: ?tags=a,b,c (compact)
- 4Indexed brackets: ?tags[0]=a&tags[1]=b (explicit order)
- 5Check your API/framework docs for the expected format
Definition
“The application/x-www-form-urlencoded format is in many ways an aberrant monstrosity... but it is nevertheless the format used for encoding form data in URLs.”— WHATWG URL Standard
Array Format Comparison
| Format | Example | Common In |
|---|---|---|
| Repeated keys | ?tag=a&tag=b&tag=c | URLSearchParams, Express |
| Empty brackets | ?tags[]=a&tags[]=b | PHP, Rails |
| Indexed brackets | ?tags[0]=a&tags[1]=b | PHP, qs library |
| Comma-separated | ?tags=a,b,c | REST APIs |
| JSON | ?tags=["a","b"] | Some APIs (needs encoding) |
Repeated Keys
https://api.example.com/products?category=electronics&category=computers&category=laptopsArray using repeated parameter keys
javascript
// JavaScript: URLSearchParams handles this naturally
const url = new URL('https://api.example.com/products');
url.searchParams.append('category', 'electronics');
url.searchParams.append('category', 'computers');
url.searchParams.append('category', 'laptops');
// Reading repeated values
const categories = url.searchParams.getAll('category');
// ['electronics', 'computers', 'laptops']
// Note: .get() only returns the first value
url.searchParams.get('category'); // 'electronics'Bracket Notation
https://api.example.com/products?tags[]=red&tags[]=blue&tags[]=greenPHP/Rails style bracket notation
javascript
// Building bracket-style parameters
const tags = ['red', 'blue', 'green'];
const params = tags.map(t => `tags[]=${encodeURIComponent(t)}`).join('&');
// "tags[]=red&tags[]=blue&tags[]=green"
// Parsing with qs library
import qs from 'qs';
const parsed = qs.parse('tags[]=red&tags[]=blue');
// { tags: ['red', 'blue'] }php
<?php
// PHP parses brackets automatically
$_GET['tags']; // ['red', 'blue', 'green']
// Building array URLs in PHP
$tags = ['red', 'blue', 'green'];
$query = http_build_query(['tags' => $tags]);
// "tags[0]=red&tags[1]=blue&tags[2]=green"Comma-Separated
https://api.example.com/products?tags=red,blue,greenComma-separated values (compact)
javascript
// Building
const tags = ['red', 'blue', 'green'];
const url = new URL('https://api.example.com/products');
url.searchParams.set('tags', tags.join(','));
// "?tags=red,blue,green"
// Parsing
const tagsParam = url.searchParams.get('tags');
const tagsArray = tagsParam ? tagsParam.split(',') : [];
// ['red', 'blue', 'green']
// Watch out for values containing commas!
const genres = ['Rock', 'R&B, Soul', 'Hip-Hop'];
url.searchParams.set('genres', genres.join(','));
// genres=Rock,R%26B%2C+Soul,Hip-Hop
// Splitting by comma would break "R&B, Soul"!Indexed Brackets
https://api.example.com/sort?fields[0]=name&fields[1]=date&order[0]=asc&order[1]=descIndexed brackets for ordered arrays
javascript
// Using qs library for complex cases
import qs from 'qs';
const data = {
fields: ['name', 'date', 'price'],
order: ['asc', 'desc', 'asc']
};
qs.stringify(data, { arrayFormat: 'indices' });
// "fields[0]=name&fields[1]=date&fields[2]=price&order[0]=asc&order[1]=desc&order[2]=asc"
qs.stringify(data, { arrayFormat: 'brackets' });
// "fields[]=name&fields[]=date&fields[]=price&order[]=asc&order[]=desc&order[]=asc"
qs.stringify(data, { arrayFormat: 'repeat' });
// "fields=name&fields=date&fields=price&order=asc&order=desc&order=asc"
qs.stringify(data, { arrayFormat: 'comma' });
// "fields=name,date,price&order=asc,desc,asc"Framework-Specific Behavior
| Framework | Default Format | Notes |
|---|---|---|
| Express.js | Repeated keys | req.query.key returns array |
| PHP | Brackets | $_GET parses [] automatically |
| Rails | Brackets | params[:key] returns array |
| Django | Repeated keys | request.GET.getlist() |
| Spring | Repeated/comma | Configurable |
| ASP.NET | Repeated keys | Request.Query returns StringValues |