晋军退到城濮停了下来。这时,齐、秦、宋各国的军队也陆续到达城濮和晋军会师。晋文公检阅了军队,认为可以与楚军决战。这时,楚军追了九十里也到达城濮,选择了有利地形扎下营寨。随后就派使者向晋文公挑战。晋文公很有礼貌地派了晋国使节回复子玉说:“晋侯只因不敢忘记楚王的恩惠,所以退避到这里。既然这样仍得不到大夫(指子玉)的谅解,那也只好决战一场了。”于是双方约定了开战的时间。
公元前 632 年 4 月 4 日,晋、楚两军决战开始。晋军针对楚军中军强大,左右翼军薄弱的部署特点,和楚军统帅子玉骄傲轻敌、不谙虚实的弱点,发起了有针对性的攻击。晋下军佐将胥臣把驾车的马蒙上虎皮,出其不意地首先向楚军中战斗力最差的右军——陈、蔡军进攻,陈、蔡军遭到这一突然而奇异的进攻,惊慌失措,弃阵逃跑,楚军右翼就这样迅速崩溃了。
晋军同时也把进攻的矛头指向楚军左翼。晋上军主将狐毛在指挥车上故意竖起两面镶有彩带的大旗,非常醒目,远远就可望见。狐毛和许、郑联军一接触,就故意败下阵来。在逃跑时,在车后面拖了很多树枝,树枝刮起的尘土遮天蔽日,给在高处观阵的子玉造成错觉,以为晋军溃不成军了,于是急令左翼部队奋勇追杀。晋中军元帅先轸等人见楚军已被诱至,便指挥中军横击楚军,晋上军主将狐毛回军夹击楚军左翼。楚军左翼退路被切断,陷入重围,基本被歼灭。子玉见左、右两翼军队都已失败,急忙下令收兵,才保住中军,退出战场。城濮之战最终以晋胜楚败而告终。