It means unlimited, and it is fine on a development site with forty posts. The site it eventually runs on has forty thousand.
// the usual culprit: building a select for an admin screen
$all = get_posts( array( 'numberposts' => -1, 'post_type' => 'product' ) );
// what it should be
$ids = get_posts( array(
'numberposts' => 500,
'post_type' => 'product',
'fields' => 'ids', // no objects, no meta priming
'no_found_rows' => true, // skips the second count query
) );
fields => 'ids' changes the cost most, because hydrating post objects also primes the meta and term caches for every one of them. no_found_rows removes a full count that only matters when paginating. Where the requirement genuinely is every post — an export, a migration — the answer is batching by ID range rather than a larger limit, and doing it in WP-CLI rather than in a request.