May 11, 2020
The 30-Minute Meal Myth
Article-Recipe-Cook-Times

If you’re finding yourself taking three times as long to make dinner as the recipe says, you’re not alone.

We’ve all fallen for the trap before. Wooed by the promise of pan-seared chicken thighs in 30 minutes, only to be defeated and left overanalyzing what went wrong more than an hour later. Or worse, we’ve thrown some onions in a pan to caramelize while we’re searing a batch of burgers, only to find ourselves still stirring the onions dejectedly, 45 minutes later.

Even as someone who writes about food for a living, I find myself confronting the same pitfalls. A quick glance at a recipe assures me that dinner will be ready in half an hour. It’s right there, staring at me. Cook time: 30 minutes. But a closer look at the ingredients says otherwise. Five garlic cloves, minced. One stalk of celery, thinly sliced on the bias. Two carrots, peeled and chopped. One yellow onion, finely diced. There go 15 minutes already (on a good day, with a sharp knife, and no distractions), which doesn’t even account for the five minutes needed to compose myself after tearfully hacking at an onion. And that’s only half the battle, if we’re counting the unglamorous process of washing and thoroughly drying all of those vegetables.

Recently I fell into a similar trap after being convinced by a trusted blog that 35 minutes was all I would need to make mapo tofu in my Brooklyn kitchen.

After pulverizing Sichuan peppercorns with a mortar and pestle, peeling and mincing a three-inch knob of ginger, finely chopping half a head of garlic, and rummaging through my dish rack to get enough small bowls and spoons to premeasure the rest of the ingredients, I’d already blown past the 20-minute mark, and I hadn’t even turned on the stove. What’s missing is the fine print of a recipe that reminds us how time-consuming zesting, chopping, and juicing can really be—on top of the many uncertainties that it takes to evenly cook everything. But most recipe writers don’t go there.

I suspected that I wasn’t alone in thinking that many recipes are written with inaccurate cook times, so I took to my Instagram to conduct an informal poll, asking home cooks, “Have you ever cooked a recipe that took way longer than it said it should?” I then sifted through a deluge of responses, most of which captured the same sentiment, i.e. “Every. Single. Recipe.” and “Caramelized onions in 10 minutes, my ass.”

Beneath a fish taco recipe advertised as a “fast dinner for hungry, busy people” in the New York Times, a comment reads, “It’s unbelievably condescending to claim this meal takes 30 minutes. It took me 15 minutes just to make the salsa, 7 for the mayo, 10 to warm all the tortillas, and a full 30 to fry all the fish in batches…. Great recipe, horrifically underestimated execution time, especially for those with kids running around.”

Alluding to images of teaspoons of cayenne and turmeric premeasured in tiny pinch bowls and neatly chopped root vegetables in their designated vessels, news producer Mike Bickal tells me, “I feel like a lot of recipes don’t consider the timing of the mise en place, as if cooking only starts when the ingredients are ready to be combined.” A lot of what’s already assumed is like a cooking segment on the Today show that fast-forwards through the boring prep and skips straight to the “effortless” frittata made vegetables that have been prewashed, dried, and julienned behind the scenes.

The conditions we’re under have their own matrices of variables. “Part of it is that recipes don’t account for skill levels—such as how fast you chop or mince and the equipment you have at your disposal,” says Kelly Chan, a Queens-based nonprofit analyst who’s often folding dumplings or prepping Cantonese-style stir-fries. Recipes are written with the presumption that all home cooks have speedy, chef-like knife skills to whiz through a mountain of shallots and tomatoes, or that they know how to butterfly a chicken without pausing, washing their hands, and looking up a YouTube tutorial. Even the Instant Pot—widely adored among home cooks for its shortcuts to complex 20-minute pho broths or five-minute steel-cut oats—still needs time to preheat and depressurize, effectively tripling the cooking time in some cases. (But of course no one tells you that, because it’s called an Instant Pot for a reason.)

More often than not, the 30-minute meal is a lie. But recipes can only account for so much. We can’t depend on them to do all the work for us. Real cooking proficiency isn’t about whipping things up without a recipe—it’s about reading between the lines of that recipe and knowing when an hour means two hours.

Tatiana Bautista

Tatiana Bautista is an assistant editor at TASTE.

[email_signup id="3"]
<div class="email-subscribe exp-subscribe subscribe"> <div class="alert alert-success exp-success ga-etembed-success" style="display:none;"> Great! You've signed up successfully! </div> <div class="alert alert-danger exp-error" style="display:none;"> We are experiencing an error, please try again. </div> <form name="subscribe" id="email-signup" class="email-signup-form" action="https://www.tastecooking.com/wp-admin/admin-ajax.php" method="POST" target="_top" data-event-assigned="false"> <fieldset class="form-group form-inline email-submit-group"> <label for="email-address" class="sr-only">Email Address</label> <input id="email-newsletter" type="email" placeholder="your@email.com" class="email-newsletter text email form-control" name="email" value=""> <button type="submit" value="Subscribe" name="subscribe" class="btn btn-primary email-submit-btn ga-etembed-success"> <i class="fa fa-envelope"></i> Subscribe </button> </fieldset> <small class="exp-small terms" style=""> By clicking Subscribe, I acknowledge that I have read and agree to the Penguin Random House <a href="http://www.penguinrandomhouse.com/privacy/" target="_blank">Privacy Policy</a> and <a href="http://www.penguinrandomhouse.com/terms/" target="_blank">Terms of Use</a> and agree to receive news and updates from TASTE and Penguin Random House. </small> <fieldset class="field-group checkboxes" style="display:none"> <div class="checkbox"> <label> <input type="checkbox" name="programs[]" value="505,50501,1" class="exp-checkbox" checked="checked"> <span><strong>Tastebook General</strong></span> </label> </div> <div class="checkbox"> <label> <input type="checkbox" name="programs[]" value="505,50502,1" class="exp-checkbox" checked="checked"> <span><strong>Tastebook Promo</strong></span> </label> </div> </fieldset><!-- /.checkboxes --> <input type="hidden" name="data_acq_code" value="TASTE_POPUP_STATIC_ONGOING" /> <input type="hidden" name="data_programs" value="50501|505,50502|505" /> <input type="hidden" name="form_id" value="3" /> <input type="hidden" name="partner" value="" /> <input type="hidden" name="action" value="crown_email_signup_submit" /> <input type="hidden" name="ref_url" value="" /> </form> </div> <script> jQuery(document).ready(function () { var unassigned_forms; setInterval( function() { //Check for unassigned forms var forms = jQuery( '.email-signup-form' ); unassigned_forms = false; forms.each( function( index ) { if ( jQuery( this ).attr( 'data-event-assigned' ) === 'false' ) { unassigned_forms = true; } }); if ( unassigned_forms ) { forms.off( 'submit' ).on( 'submit', function ( e ) { forms.attr( 'data-event-assigned', 'true' ); e.preventDefault(); // Basic email validation var email = jQuery(e.target).find('.email-newsletter').val(), valid_email = false, groupEl = jQuery(e.target).closest('.email-subscribe'); if ( !!email && typeof(email) === "string" ) { var email_array = email.split('@'); if ( email_array.length === 2 ) { if ( email_array[1].split('.').length > 1 ) { valid_email = true; } } } if ( valid_email ) { jQuery('.alert-danger').hide(); // Show loading gif groupEl.find('.email-signup-form').hide(); groupEl.find('.email-submit-loading').show(); // Populate ref_url jQuery(this).find('input[name="ref_url"]').val(window.location.href); // Generate Payload var payload = jQuery(this).serializeArray(); jQuery.ajax({ url: jQuery(this).attr('action'), type: 'POST', data: payload, success: function (data) { // Hide loading spinner groupEl.find('.email-signup-form').show(); groupEl.find('.email-submit-loading').hide(); // Display success msg var target = jQuery(e.target); jQuery(e.target).hide(); jQuery(e.target).parent().find('.alert-success').show(); jQuery(e.target).parent().find('#downloadbtn').show(); }, fail: function (err) { // Hide loading spinner groupEl.find('.email-signup-form').show(); groupEl.find('.email-submit-loading').hide(); // Display failure msg var target = jQuery(e.target); jQuery(e.target).hide(); jQuery(e.target).parent().find('.alert-danger').show(); } }); } else { groupEl.find('.alert-danger').html('Please enter a valid email address.').show(); } }); forms.off( 'keypress' ).on( 'keypress', function ( e ) { if ( e.which === 13 ) { e.preventDefault(); jQuery( this ).submit(); } }); } }, 100); }); </script>
[email_signup id="3"]
<div class="email-subscribe exp-subscribe subscribe"> <div class="alert alert-success exp-success ga-etembed-success" style="display:none;"> Great! You've signed up successfully! </div> <div class="alert alert-danger exp-error" style="display:none;"> We are experiencing an error, please try again. </div> <form name="subscribe" id="email-signup" class="email-signup-form" action="https://www.tastecooking.com/wp-admin/admin-ajax.php" method="POST" target="_top" data-event-assigned="false"> <fieldset class="form-group form-inline email-submit-group"> <label for="email-address" class="sr-only">Email Address</label> <input id="email-newsletter" type="email" placeholder="your@email.com" class="email-newsletter text email form-control" name="email" value=""> <button type="submit" value="Subscribe" name="subscribe" class="btn btn-primary email-submit-btn ga-etembed-success"> <i class="fa fa-envelope"></i> Subscribe </button> </fieldset> <small class="exp-small terms" style=""> By clicking Subscribe, I acknowledge that I have read and agree to the Penguin Random House <a href="http://www.penguinrandomhouse.com/privacy/" target="_blank">Privacy Policy</a> and <a href="http://www.penguinrandomhouse.com/terms/" target="_blank">Terms of Use</a> and agree to receive news and updates from TASTE and Penguin Random House. </small> <fieldset class="field-group checkboxes" style="display:none"> <div class="checkbox"> <label> <input type="checkbox" name="programs[]" value="505,50501,1" class="exp-checkbox" checked="checked"> <span><strong>Tastebook General</strong></span> </label> </div> <div class="checkbox"> <label> <input type="checkbox" name="programs[]" value="505,50502,1" class="exp-checkbox" checked="checked"> <span><strong>Tastebook Promo</strong></span> </label> </div> </fieldset><!-- /.checkboxes --> <input type="hidden" name="data_acq_code" value="TASTE_POPUP_STATIC_ONGOING" /> <input type="hidden" name="data_programs" value="50501|505,50502|505" /> <input type="hidden" name="form_id" value="3" /> <input type="hidden" name="partner" value="" /> <input type="hidden" name="action" value="crown_email_signup_submit" /> <input type="hidden" name="ref_url" value="" /> </form> </div> <script> jQuery(document).ready(function () { var unassigned_forms; setInterval( function() { //Check for unassigned forms var forms = jQuery( '.email-signup-form' ); unassigned_forms = false; forms.each( function( index ) { if ( jQuery( this ).attr( 'data-event-assigned' ) === 'false' ) { unassigned_forms = true; } }); if ( unassigned_forms ) { forms.off( 'submit' ).on( 'submit', function ( e ) { forms.attr( 'data-event-assigned', 'true' ); e.preventDefault(); // Basic email validation var email = jQuery(e.target).find('.email-newsletter').val(), valid_email = false, groupEl = jQuery(e.target).closest('.email-subscribe'); if ( !!email && typeof(email) === "string" ) { var email_array = email.split('@'); if ( email_array.length === 2 ) { if ( email_array[1].split('.').length > 1 ) { valid_email = true; } } } if ( valid_email ) { jQuery('.alert-danger').hide(); // Show loading gif groupEl.find('.email-signup-form').hide(); groupEl.find('.email-submit-loading').show(); // Populate ref_url jQuery(this).find('input[name="ref_url"]').val(window.location.href); // Generate Payload var payload = jQuery(this).serializeArray(); jQuery.ajax({ url: jQuery(this).attr('action'), type: 'POST', data: payload, success: function (data) { // Hide loading spinner groupEl.find('.email-signup-form').show(); groupEl.find('.email-submit-loading').hide(); // Display success msg var target = jQuery(e.target); jQuery(e.target).hide(); jQuery(e.target).parent().find('.alert-success').show(); jQuery(e.target).parent().find('#downloadbtn').show(); }, fail: function (err) { // Hide loading spinner groupEl.find('.email-signup-form').show(); groupEl.find('.email-submit-loading').hide(); // Display failure msg var target = jQuery(e.target); jQuery(e.target).hide(); jQuery(e.target).parent().find('.alert-danger').show(); } }); } else { groupEl.find('.alert-danger').html('Please enter a valid email address.').show(); } }); forms.off( 'keypress' ).on( 'keypress', function ( e ) { if ( e.which === 13 ) { e.preventDefault(); jQuery( this ).submit(); } }); } }, 100); }); </script>